Skip to content

Fix ExifTool crashes and improve write support#257

Merged
fglock merged 6 commits into
masterfrom
fix-exiftool-crashes
Mar 2, 2026
Merged

Fix ExifTool crashes and improve write support#257
fglock merged 6 commits into
masterfrom
fix-exiftool-crashes

Conversation

@fglock
Copy link
Copy Markdown
Owner

@fglock fglock commented Mar 2, 2026

Summary

This PR fixes multiple issues discovered while running ExifTool's test suite, with the most significant being a fundamental bug in \&foo code reference handling for forward-declared subs.

Key fixes:

  • \&foo for forward-declared subs returned undef instead of a CODE reference. This broke ExifTool's AUTOLOAD mechanism for lazily loading writer modules (WriteExif.pl, WritePNG.pl, etc.), causing all TIFF/EXIF write operations to fail silently. Fixed by adding IdentifierNode handling in EmitOperator's backslash handler to call RuntimeCode.createCodeReference().

  • undef $coderef didn't clear CODE type - ref(), getBoolean(), and toString() now check if a CODE value is actually defined, fixing ExifTool's PNG ProcessDirectory crash (test 7).

  • Binary data (BYTE_STRING) corruption in concat/substr/read - STRING type was "sticky" in concatenation, causing binary data round-trips to lose BYTE_STRING type. Fixed type propagation in StringOperators, RuntimeSubstrLvalue, Readline, and CustomFileChannel.

  • Encode::is_utf8() returning inverted results and inconsistent behavior between Encode::is_utf8 and utf8::is_utf8.

  • Named sub return value fix - EmitBlock was incorrectly using RETURN_VALUE opcode (pops stack) instead of storing the last expression value.

  • AUTOLOAD not triggering for forward-declared subs in bytecode interpreter.

  • New Compress::Zlib module stub for ExifTool compatibility.

  • Renamed MOVE opcode to ALIAS to fix my/our variable aliasing semantics.

ExifTool test results (baseline -> now):

Test Before After Change
CanonVRD 13 21 +8
GIF 2 5 +3
Writer 30 33 +3
IPTC 7 8 +1
GeoTiff 3 4 +1
PLUS 2 3 +1
PPM 2 3 +1
XMP 40 41 +1
PNG 4+crash 5 +1, no crash

Test plan

  • make passes (build + unit tests)
  • make test-unit passes (all shards)
  • ExifTool test suite shows improvements across all tested modules
  • No regressions in existing unit tests

Generated with Devin

fglock and others added 4 commits March 1, 2026 23:53
…dling

- Fix undef $coderef: ref() now returns "" and boolean is false for
  undefined CODE scalars, matching Perl 5 behavior. undef &foo still
  correctly reports "Undefined subroutine" on call.

- Add Compress::Zlib module using java.util.zip for inflate/deflate,
  enabling ExifTool's PNG, PDF, and other compressed format support.

- Fix Encode::is_utf8/utf8::is_utf8 to only return true for strings
  with actual wide characters (>255), preventing binary data corruption
  in ExifTool's ParseArguments.

- Fix slurp-mode readline when $/ is undef (local $/), preserving
  BYTE_STRING type for binary data.

- Fix named sub definition return values: skip compile-time-only nodes
  when computing block return value, fixing modules without explicit 1;
  before __END__.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
\&foo where foo was only forward-declared (sub foo;) was returning
undef instead of a CODE reference. This broke ExifTool's AUTOLOAD
mechanism for lazily loading write modules (WriteExif.pl, etc),
causing all TIFF/EXIF write operations to fail.

The fix adds an IdentifierNode case in EmitOperator's backslash
handler that creates a RuntimeScalar with the sub name and calls
createCodeReference, matching how Perl 5 handles \& on stash entries.

Also make Utf8.java is_utf8 consistent (true for all non-BYTE_STRING)
and fix perl_test_runner.pl to not chdir for ExifTool tests.

ExifTool test improvements vs baseline:
  GIF: 2→5, IPTC: 7→8, GeoTiff: 3→4, PLUS: 2→3,
  PPM: 2→3, Writer: 30→33, CanonVRD: 13→21, XMP: 40→41,
  PNG: 4+crash→5

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
The previous change to skip empty ListNodes when finding the last
expression in a block caused sub foo($a) { } to return the argument
value instead of undef. The \&foo code reference fix was the actual
solution for the ExifTool named sub return issue.

Fixes 13 regressions in op/signatures.t (589→602).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
…an context

In Perl 5, all code references are truthy regardless of whether the sub
body is defined. Changed getBooleanLarge() CODE case to return true
(zero memory cost). This fixes can() returning falsy for forward-declared
subs (uni/universal.t test 16) while preserving identity comparison
(mro/basic.t test 56).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
@fglock fglock force-pushed the fix-exiftool-crashes branch from 948abc9 to 52f7409 Compare March 2, 2026 09:02
fglock and others added 2 commits March 2, 2026 10:39
Previously alarm only worked in the JVM codegen path. Add ALARM_OP
(opcode 155) with compilation, interpretation, and disassembly support
so alarm works correctly in eval STRING contexts.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
…stem alarm, stale flag cleanup

- select(undef,undef,undef,timeout): dispatch pending signals on
  InterruptedException, clear stale interrupt before sleeping (fixes
  sigdispatch.t tests 22-23)
- kill to self-PID: route through PerlSignalQueue instead of sending
  real OS signals that crash the JVM (fixes sigdispatch.t test 28)
- PerlSignalQueue: clear thread interrupt flag and update hasPendingSignal
  before handler invocation so die in handlers does not leave stale state
- system(): dispatch pending signals on InterruptedException instead of
  throwing PerlCompilerException (fixes alarm.t tests 3-4)

sigdispatch.t: 23/29 -> 26/29, alarm.t: 3/5 -> 5/5

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
@fglock fglock force-pushed the fix-exiftool-crashes branch from 7ac5330 to 94389eb Compare March 2, 2026 10:10
@fglock fglock merged commit b3e89af into master Mar 2, 2026
2 checks passed
@fglock fglock deleted the fix-exiftool-crashes branch March 2, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant