Skip to content

Commit 342c95e

Browse files
committed
Fix multiple issues in t/op/magic.t
This commit fixes several critical issues in the magic variables test suite: 1. Fix RuntimeGlob cannot be cast to RuntimeCode crash (line 745) - Separated CODE and GLOB cases in RuntimeScalar.toStringRef() - Previously both cases were handled together causing incorrect type casting - Fixes fatal crash when converting glob to string reference 2. Initialize $^T magic variable with epoch time (test 98) - Added initialization of $^T to current Unix timestamp in GlobalContext - $^T represents script start time in seconds since epoch 3. Make ${^TAINT} read-only (test 127) - Use existing RuntimeScalarCache.scalarZero for ${^TAINT} - Leverages existing RuntimeScalarReadOnly infrastructure for immutability - Properly throws 'Modification of a read-only value' exception on write 4. Prevent auto-vivification of glob slots (test 85) - Modified RuntimeGlob.hashDerefGet() to check slot existence - *glob{HASH} and *glob{ARRAY} now return undef if slots don't exist - Prevents unwanted creation of hash/array slots on access Test Results: - Before: Multiple failures including fatal crash - After: 158/208 tests passing (76% pass rate) - Eliminated fatal crash, improved stability Files Modified: - RuntimeScalar.java: Fixed glob/code toStringRef() handling - GlobalContext.java: Initialize $^T, use scalarZero for ${^TAINT} - RuntimeGlob.java: Check existence before auto-vivifying slots
1 parent 4e59947 commit 342c95e

File tree

3 files changed

+23
-4
lines changed

3 files changed

+23
-4
lines changed

src/main/java/org/perlonjava/runtime/GlobalContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public static void initializeGlobals(CompilerOptions compilerOptions) {
4646
}
4747
GlobalVariable.getGlobalVariable("main::" + Character.toString('O' - 'A' + 1)).set(SystemUtils.getPerlOsName()); // initialize $^O
4848
GlobalVariable.getGlobalVariable("main::" + Character.toString('V' - 'A' + 1)).set(Configuration.getPerlVersionVString()); // initialize $^V
49+
GlobalVariable.getGlobalVariable("main::" + Character.toString('T' - 'A' + 1)).set((int)(System.currentTimeMillis() / 1000)); // initialize $^T to epoch time
4950

5051
// Initialize $^X - the name used to execute the current copy of Perl
5152
// PERLONJAVA_EXECUTABLE is set by the `jperl` or `jperl.bat` launcher
@@ -71,7 +72,7 @@ public static void initializeGlobals(CompilerOptions compilerOptions) {
7172
GlobalVariable.getGlobalVariable("main::?");
7273
GlobalVariable.getGlobalVariable("main::0").set(compilerOptions.fileName);
7374
GlobalVariable.getGlobalVariable(GLOBAL_PHASE).set(""); // ${^GLOBAL_PHASE}
74-
GlobalVariable.getGlobalVariable(encodeSpecialVar("TAINT")); // ${^TAINT}
75+
GlobalVariable.globalVariables.put(encodeSpecialVar("TAINT"), RuntimeScalarCache.scalarZero); // ${^TAINT} - read-only, always 0 (taint mode not implemented)
7576
GlobalVariable.getGlobalVariable("main::>"); // TODO
7677
GlobalVariable.getGlobalVariable("main::<"); // TODO
7778
GlobalVariable.getGlobalVariable("main::;").set("\034"); // initialize $; (SUBSEP) to \034

src/main/java/org/perlonjava/runtime/RuntimeGlob.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,20 @@ public RuntimeScalar hashDerefGet(RuntimeScalar index) {
186186
case "CODE" -> GlobalVariable.getGlobalCodeRef(this.globName);
187187
case "IO" -> IO;
188188
case "SCALAR" -> GlobalVariable.getGlobalVariable(this.globName);
189-
case "ARRAY" -> GlobalVariable.getGlobalArray(this.globName).createReference();
190-
case "HASH" -> GlobalVariable.getGlobalHash(this.globName).createReference();
189+
case "ARRAY" -> {
190+
// Only return reference if array exists (has elements or was explicitly created)
191+
if (GlobalVariable.existsGlobalArray(this.globName)) {
192+
yield GlobalVariable.getGlobalArray(this.globName).createReference();
193+
}
194+
yield new RuntimeScalar(); // Return undef if array doesn't exist
195+
}
196+
case "HASH" -> {
197+
// Only return reference if hash exists (has elements or was explicitly created)
198+
if (GlobalVariable.existsGlobalHash(this.globName)) {
199+
yield GlobalVariable.getGlobalHash(this.globName).createReference();
200+
}
201+
yield new RuntimeScalar(); // Return undef if hash doesn't exist
202+
}
191203
case "FORMAT" -> GlobalVariable.getGlobalFormatRef(this.globName);
192204
default -> new RuntimeScalar();
193205
};

src/main/java/org/perlonjava/runtime/RuntimeScalar.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,12 +685,18 @@ private String toStringLarge() {
685685
public String toStringRef() {
686686
String ref = switch (type) {
687687
case UNDEF -> "SCALAR(0x" + scalarUndef.hashCode() + ")";
688-
case CODE, GLOB -> {
688+
case CODE -> {
689689
if (value == null) {
690690
yield "CODE(0x" + scalarUndef.hashCode() + ")";
691691
}
692692
yield ((RuntimeCode) value).toStringRef();
693693
}
694+
case GLOB -> {
695+
if (value == null) {
696+
yield "GLOB(0x" + scalarUndef.hashCode() + ")";
697+
}
698+
yield ((RuntimeGlob) value).toStringRef();
699+
}
694700
case VSTRING -> "VSTRING(0x" + value.hashCode() + ")";
695701
default -> "SCALAR(0x" + Integer.toHexString(value.hashCode()) + ")";
696702
};

0 commit comments

Comments
 (0)