Skip to content

Fix $^H scope leakage and add I18N::Langinfo module#372

Merged
fglock merged 7 commits into
masterfrom
fix/hints-scope-leakage
Mar 25, 2026
Merged

Fix $^H scope leakage and add I18N::Langinfo module#372
fglock merged 7 commits into
masterfrom
fix/hints-scope-leakage

Conversation

@fglock
Copy link
Copy Markdown
Owner

@fglock fglock commented Mar 25, 2026

Summary

This PR includes several related fixes discovered during DateTime/I18N::Langinfo testing:

1. Fix version->parse() to handle undef values (Version.java)

Fixes "Invalid version format (non-numeric data)" error when MM->parse_version() returns undef or the literal string "undef" for modules without version numbers.

2. Fix $^H scope leakage (ScalarSpecialVariable.java)

Fixes a bug where use locale (or any module modifying $^H) after use Test::More was incorrectly enabling strict mode in the outer scope.

Problem: The $^H (compile-time hints) special variable was caching values in a shared lvalue field. When Test::More enabled strict mode, the strict bits got cached. Later when locale.pm read $^H, it got the stale cached value.

Fix:

  • Remove lvalue caching for HINTS in vivify()
  • Change set() to only update the scope's strict options via symbol table
  • Change getValueAsScalar() HINTS case to always read from current scope's symbol table

3. Fix $^H propagation between BEGIN blocks (PerlLanguageProvider.java)

Fixes $^H values not persisting between BEGIN blocks in the same lexical scope.

Fix: Propagate $^H (strictOptions) bi-directionally between caller scope and BEGIN block execution scope.

4. Add I18N::Langinfo module

  • I18NLanginfo.java: Java XS implementation with langinfo() function and ~70 locale constants
  • I18N/Langinfo.pm: Imported from Perl 5 distribution
  • constant.pm: Updated to full Perl 5 version with /u modifier for Unicode constant names

5. Fix warnings::enabled() (Warnings.java)

Allow warnings::enabled() to be called without arguments (checks if warnings are enabled for the calling package). Required by the full Perl 5 constant.pm.

6. Fix ${qr//} dereference with strict refs (RuntimeScalar.java)

Add REGEX case to scalarDeref() to handle dereferencing Regexp objects. In Perl, ${qr/foo/} returns the stringified form "(?^:foo)". Previously this threw "Not a SCALAR reference" under strict refs.

Test plan

  • Original $^H scope leakage case passes: ./jperl -e 'use Test::More; use locale; $x = 1; print "OK\n"'
  • $^H persists between BEGIN blocks in same lexical scope
  • use strict still correctly enforces variable declarations
  • I18N::Langinfo works: use I18N::Langinfo qw(langinfo CODESET); print langinfo(CODESET) -> UTF-8
  • Unicode constant names work: use utf8; use constant foo => "test"
  • ${qr/(?{})/} works with strict refs enabled
  • comp/hints.t: 23/31 (improved from 21/31 on master)
  • uni/gv.t: 158/206 (same as master)
  • uni/stash.t: 33/49 (same as master)
  • op/blocks.t: 9/26 (same as master)
  • op/index.t: 415/415 (same as master)
  • op/utfhash.t: 91/99 (same as master)
  • All unit tests pass (make)

Generated with Devin

fglock and others added 2 commits March 25, 2026 10:15
The $^H (compile-time hints) variable was using a shared lvalue field
to cache values. When Test::More enabled strict mode, the strict bits
were cached in lvalue. Later when locale.pm read $^H, it got the stale
cached value instead of the current scope's value, causing strict mode
to incorrectly leak into outer scopes.

Fix:
- Remove lvalue caching for HINTS in vivify() - return without storing
- Change set() to only update the scope's strict options, not the cache
- Change getValueAsScalar() HINTS case to always read from the current
  scope's symbol table via SpecialBlockParser.getCurrentScope()

This ensures $^H respects lexical scoping - each scope has its own value.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add I18NLanginfo.java: Java XS implementation with langinfo() function
  and ~70 locale constants (CODESET, RADIXCHAR, DAY_1-7, MON_1-12, etc.)
- Import I18N/Langinfo.pm from Perl 5 distribution
- Update constant.pm to full Perl 5 version (was simplified stub)
- Add I18N::Langinfo to import config

This fixes 07locale.t test (was 1/8, now 8/8 passing).

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@fglock fglock force-pushed the fix/hints-scope-leakage branch from d781b3e to 67a4521 Compare March 25, 2026 09:16
@fglock fglock changed the title Fix $^H scope leakage causing use locale to enable strict Fix $^H scope leakage and add I18N::Langinfo module Mar 25, 2026
fglock and others added 5 commits March 25, 2026 10:17
Perl's version->parse(undef) and version->parse("undef") both return
version 0. PerlOnJava was throwing "Invalid version format (non-numeric
data)" instead.

This fix is needed for CPAN module testing where ExtUtils::MakeMaker's
MM->parse_version() returns the literal string "undef" for modules
without version numbers (e.g., Dist::CheckConflicts, warnings::register).

Changes:
- Handle RuntimeScalarType.UNDEF by treating as version "0"
- Handle literal string "undef" by treating as version "0"
- Restructure validation to skip when handling undef cases

Fixes DateTime test suite t/00-report-prereqs.t failure.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- PerlLanguageProvider: Propagate $^H (strictOptions) bi-directionally between
  caller scope and BEGIN block execution scope. This ensures that:
  1. BEGIN blocks inherit $^H from the enclosing lexical scope
  2. Changes to $^H in BEGIN blocks persist for subsequent code in the same scope

- RuntimeRegex: Use Unicode pattern (UNICODE_CHARACTER_CLASS) when the string
  has the UTF-8 flag set, regardless of whether characters are > 255. This fixes
  \\w matching Latin-1 characters like è (U+00E8) in UTF-8 strings.

- Warnings: Allow warnings::enabled() to be called without arguments (checks
  if warnings are enabled for the calling package). Required by constant.pm.

Test results vs master:
- comp/hints.t: 23/31 (was 21/31) - improved by 2 tests
- uni/gv.t: 158/206 (same as master)
- uni/stash.t: 33/49 (same as master)
- op/blocks.t: 9/26 (same as master)

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add REGEX case to scalarDeref() to handle dereferencing Regexp objects.
In Perl, ${qr/foo/} returns the stringified form "(?^:foo)".
Previously this threw "Not a SCALAR reference" under strict refs.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Revert the Unicode pattern change from commit abba6b9.
The change exposed a pre-existing bug where hash keys lose their
byte/UTF-8 flag, causing op/utfhash.t to regress from 91/99 to 89/99.

Keep the hasUnicodeChars check to avoid the regression.
The underlying hash key UTF-8 flag issue is a separate bug to fix later.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add /u modifier to regex patterns for validating constant names.
Without this, UTF-8 constant names fail validation because
\w does not match Unicode word characters by default.

Fixes uni/gv.t and uni/stash.t tests.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@fglock fglock merged commit 3a54b2f into master Mar 25, 2026
2 checks passed
@fglock fglock deleted the fix/hints-scope-leakage branch March 25, 2026 11:01
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