Fix local *FH pattern for independent filehandles and add fileno support#385
Merged
Conversation
When using `do { local *FH; *FH }` to create multiple filehandle copies,
each copy now gets its own independent IO slot. Previously, all copies
shared the same IO reference, causing files opened on one copy to
overwrite files opened on another copy.
Changes:
- RuntimeGlob.createDetachedCopy(): Create a new IO RuntimeScalar instead
of sharing the reference
- EmitVariable.java: Call createDetachedCopy() when returning globs
- SlowOpcodeHandler.java: Same change for interpreter backend
- IOOperator.java: Update global glob when opening named filehandles
Fixes Log::Log4perl t/026FileApp.t test failure.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When doing *FH = *TESTFILE, the set(RuntimeGlob) method was only updating the detached copy IO slot, not the global glob. This caused <FH> to fail because the global FH IO was still empty. The fix updates both the detached copy AND the global glob IO slot. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When calling opendir(DIR, path), the glob DIR is a detached copy. The fix ensures the global glob's IO is also updated, matching the fix already applied to open() in IOOperator.java. This fixes regressions in op/stat_errors.t and other directory tests. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The previous commit incorrectly called createDetachedCopy() at glob load time, which caused each access to `*FH` to return a different glob object. This broke: - `tie *FH, ...` followed by `tied *FH` (returned undef) - Multiple references to the same glob via `\*FH` (different objects) The fix is to only create detached copies when ASSIGNING a glob to a scalar (via RuntimeScalar(RuntimeGlob) constructor), not at load time. This way: - `\*FH` returns the same glob reference each time (correct for tie/tied) - `my $fh = *FH` creates a detached copy (correct for Log::Log4perl) Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The independent IO slots caused a regression in uni/gv.t test 188
(PVLV: sv_2io stringifieth not). This test requires:
$_ = *quin;
open *quin, test.pl;
# $_ must see the IO opened through *quin
With independent IO slots, $_ had its own IO that was not updated when
opening through *quin.
Reverting to shared IO behavior:
- createDetachedCopy() shares the IO reference (copy.IO = this.IO)
- Removed redundant global glob updates from IOOperator and Directory
The Log::Log4perl do { local *FH; *FH } pattern issue remains a
pre-existing bug on master that needs a different fix approach.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The do { local *FH; open FH, ...; *FH } pattern (used by Log::Log4perl)
was creating filehandles that shared the same IO slot instead of being
independent.
Root cause: EmitOperatorLocal was calling createDetachedCopy() before
dynamicSaveState(), so local operated on a copy instead of the actual
global glob from globalIORefs.
Fix: In EmitOperatorLocal, local *GLOB now directly emits getGlobalIO()
WITHOUT createDetachedCopy(), ensuring dynamicSaveState() operates on
the actual global glob.
Also added synthetic fileno support to CustomFileChannel since Java
does not expose OS file descriptors.
Generated with Devin: https://cli.devin.ai/docs
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The glob assignment *FH = *TESTFILE was not properly updating the global glob's IO slot, only updating the detached copy. Now we update both. Also added fd recycling for synthetic file descriptors - when a CustomFileChannel is closed, its fd is returned to a pool for reuse. This makes fileno() return more stable values. Test results: - base/rs.t: Now passes 41/41 (was 21/41) - FIXED - run/switchF1.t: Now passes 5/5 - FIXED - local_glob_filehandle.t: Passes 5/5 - core bug fix verified - io/perlio_leaks.t: Fails due to JVM GC (no scope-based fd cleanup) - io/dup.t: Pre-existing failures (same on master) - comp/proto.t: Pre-existing failures (same on master) Generated with Devin: https://cli.devin.ai/docs Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
94be062 to
280f92c
Compare
Add hashCode() and equals() overrides to RuntimeGlob based on globName. This ensures that detached copies (used by local *FH) compare equal to the original glob, fixing the regression in comp/proto.t where `\*FOO eq \*FOO` was returning false. - hashCode() returns globName.hashCode() so all copies stringify the same - equals() compares globName so \*FOO eq \*FOO works correctly - Revert unnecessary fileno changes (not needed for the core fix) - Simplify test file Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
getDoubleRef() now returns Integer.toUnsignedLong(hashCode()) to match what hex() returns when parsing the stringified address. This fixes op/bless.t and uni/bless.t tests that compare hex(address) == object. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
do { local *FH; open FH, ...; *FH }pattern (used by Log::Log4perl) was creating filehandles that shared the same IO slot instead of being independent.Root Cause
In
EmitOperatorLocal.java, when processinglocal *FH, the code was callingcreateDetachedCopy()beforedynamicSaveState(), so local operated on a copy instead of the actual global glob fromglobalIORefs. Later*FHaccesses returned the original glob (unmodified by local).Fix
local *GLOBnow directly emitsgetGlobalIO()WITHOUTcreateDetachedCopy(), ensuringdynamicSaveState()operates on the actual global globTest Plan
local_glob_filehandle.tpasses (tests independent filehandles, Log::Log4perl pattern)makepasses all testsGenerated with Devin