Skip to content

Fix ExifTool and package refactor#251

Merged
fglock merged 9 commits into
masterfrom
fix-exiftool-and-package-refactor
Feb 28, 2026
Merged

Fix ExifTool and package refactor#251
fglock merged 9 commits into
masterfrom
fix-exiftool-and-package-refactor

Conversation

@fglock
Copy link
Copy Markdown
Owner

@fglock fglock commented Feb 28, 2026

Summary

  • Fix AUTOLOAD dispatch order: search full MRO hierarchy (including UNIVERSAL) before checking AUTOLOAD. Previously AUTOLOAD was checked per-class, intercepting UNIVERSAL methods like can(), isa()
  • Fix can() to return coderef for forward declarations (sub foo;)
  • More fixes coming (FileSize/stat, package-as-compile-time-constant refactor)

Test plan

  • make (unit tests pass)
  • Image::ExifTool test suite: ExifTool.t improved from 12/35 to 24/35
  • Full ExifTool suite re-test after further fixes
  • Perl5 core test suite regression check

Generated with Devin

fglock and others added 9 commits February 28, 2026 14:53
In Perl, AUTOLOAD is only checked after the entire class hierarchy
(including UNIVERSAL) has been searched for the method. Previously,
AUTOLOAD was checked per-class during the hierarchy walk, causing
UNIVERSAL methods like can(), isa() to be intercepted by AUTOLOAD
in classes that define it (e.g. Image::ExifTool).

Split findMethodInHierarchy into two passes:
1. Search all classes for the actual method
2. Only then search for AUTOLOAD

Also fix can() to return coderef for forward declarations (sub foo;)
which exist in the stash but are not yet defined.

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

Co-Authored-By: Devin <noreply@cognition.ai>
- Store file path in CustomFileChannel so -f $fh and stat($fh) can
  resolve the underlying path from LayeredIOHandle delegates
- Fix stat _ parser: move underscore check before bareword filehandle
  handler which was intercepting _ as a glob reference
- Add STAT_LASTHANDLE/LSTAT_LASTHANDLE opcodes for bytecode interpreter
  so stat _ uses cached stat buffer instead of re-statting

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

Co-Authored-By: Devin <noreply@cognition.ai>
f((expr) * y) was wrongly rejected as "too many arguments" when the
subroutine had an @ prototype. The parseZeroOrMoreList call was using
obeyParentheses=true, which mistook inner grouping parens for an
argument list boundary.

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

Co-Authored-By: Devin <noreply@cognition.ai>
Emit CREATE_GOTO + RETURN opcodes for goto LABEL statements,
matching the JVM backend non-local goto control flow via
RuntimeControlFlowList with ControlFlowType.GOTO.

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

Co-Authored-By: Devin <noreply@cognition.ai>
The UnpackState constructor was using UTF-8 byte encoding when the
source scalar had the utf8 flag set, even when all code points were
<= 255. This caused bytes like 0x80 to be encoded as 0xC2 0x80,
corrupting numeric unpack formats (f, d, N, etc.).

Split isUTF8Data (controls byte encoding) from isUTF8Flagged (controls
A* whitespace trimming) so binary data always uses ISO-8859-1 encoding.

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

Co-Authored-By: Devin <noreply@cognition.ai>
In Perl, \4 and \17 inside [] are octal, but Java treats \N as a
backreference. Prepend 0 to make them unambiguous Java octal escapes.
Handle both 1-digit and 2-digit octal sequences correctly.

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

Co-Authored-By: Devin <noreply@cognition.ai>
When using `foreach $var (...)` where $var was declared earlier with `my`,
the bytecode compiler allocated a fresh register instead of reusing the
existing one. FOREACH_NEXT_OR_EXIT wrote to the new register while the
loop body read from the original, causing $var to appear empty.

Now checks for pre-existing lexical variables and reuses their register.

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

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

Clean up BEGIN aliases for captured variables in evalStringHelper finally
block after compilation completes. These aliases (inserted into GlobalVariable
so BEGIN blocks can access outer lexicals during parsing) were persisting
beyond their useful lifetime, causing retrieveBeginScalar to return stale
shared objects instead of fresh variables on recursive function calls.

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

Co-Authored-By: Devin <noreply@cognition.ai>
statLastHandle/lstatLastHandle were re-statting the last file argument
instead of returning the cached stat result. This caused stat _ after a
failed stat to return the wrong errno (e.g. ENOENT instead of EBADF).

Also ensure $! is correctly set in scalar context paths.

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

Co-Authored-By: Devin <noreply@cognition.ai>
@fglock fglock merged commit 7c6c89f into master Feb 28, 2026
2 checks passed
@fglock fglock deleted the fix-exiftool-and-package-refactor branch February 28, 2026 19:16
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