diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b61ad8a6e..da56014c2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,10 +1,10 @@ [versions] asm = "9.10.1" -bouncycastle = "1.84" +bouncycastle = "1.85" commons-compress = "1.28.0" commons-csv = "1.14.1" icu4j = "78.3" -junit-jupiter = "6.1.1" +junit-jupiter = "6.1.2" snakeyaml-engine = "3.0.1" sqlite-jdbc = "3.53.2.0" tomlj = "1.1.1" diff --git a/pom.xml b/pom.xml index a7615aede..78c2dbd0e 100644 --- a/pom.xml +++ b/pom.xml @@ -30,19 +30,19 @@ org.junit.jupiter junit-jupiter-api - 6.1.1 + 6.1.2 test org.junit.jupiter junit-jupiter-engine - 6.1.1 + 6.1.2 test org.junit.jupiter junit-jupiter-params - 6.1.1 + 6.1.2 test @@ -78,12 +78,12 @@ org.bouncycastle bcprov-jdk18on - 1.84 + 1.85 org.bouncycastle bcpkix-jdk18on - 1.84 + 1.85 io.netty diff --git a/src/main/perl/lib/JSON/PP.pm b/src/main/perl/lib/JSON/PP.pm index 266a17429..cfa767e72 100644 --- a/src/main/perl/lib/JSON/PP.pm +++ b/src/main/perl/lib/JSON/PP.pm @@ -15,7 +15,7 @@ use Carp (); use Scalar::Util qw(blessed reftype refaddr); #use Devel::Peek; -our $VERSION = '4.16'; +our $VERSION = '4.18'; our @EXPORT = qw(encode_json decode_json from_json to_json); @@ -112,7 +112,7 @@ sub encode_json ($) { # encode } -sub decode_json { # decode +sub decode_json ($) { # decode ($JSON ||= __PACKAGE__->new->utf8)->decode(@_); } @@ -329,50 +329,21 @@ sub allow_bigint { { # Convert - my $max_depth; - my $indent; - my $ascii; - my $latin1; - my $utf8; - my $space_before; - my $space_after; - my $canonical; - my $allow_blessed; - my $convert_blessed; - - my $indent_length; - my $escape_slash; - my $bignum; - my $as_nonblessed; - my $allow_tags; - - my $depth; - my $indent_count; - my $keysort; - - sub PP_encode_json { my $self = shift; my $obj = shift; - $indent_count = 0; - $depth = 0; + $self->{indent_count} = 0; + $self->{depth} = 0; my $props = $self->{PROPS}; - ($ascii, $latin1, $utf8, $indent, $canonical, $space_before, $space_after, $allow_blessed, - $convert_blessed, $escape_slash, $bignum, $as_nonblessed, $allow_tags) - = @{$props}[P_ASCII .. P_SPACE_AFTER, P_ALLOW_BLESSED, P_CONVERT_BLESSED, - P_ESCAPE_SLASH, P_ALLOW_BIGNUM, P_AS_NONBLESSED, P_ALLOW_TAGS]; - - ($max_depth, $indent_length) = @{$self}{qw/max_depth indent_length/}; - - $keysort = $canonical ? sub { $a cmp $b } : undef; + $self->{keysort} = $self->{PROPS}[P_CANONICAL] ? sub { $a cmp $b } : undef; if ($self->{sort_by}) { - $keysort = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by} - : $self->{sort_by} =~ /\D+/ ? $self->{sort_by} - : sub { $a cmp $b }; + $self->{keysort} = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by} + : $self->{sort_by} =~ /\D+/ ? $self->{sort_by} + : sub { $a cmp $b }; } encode_error("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)") @@ -380,7 +351,7 @@ sub allow_bigint { my $str = $self->object_to_json($obj); - $str .= "\n" if ( $indent ); # JSON::XS 2.26 compatible + $str .= "\n" if ( $self->{PROPS}[P_INDENT] ); # JSON::XS 2.26 compatible return $str; } @@ -401,7 +372,7 @@ sub allow_bigint { return $self->value_to_json($obj) if ( $obj->isa('JSON::PP::Boolean') ); - if ( $allow_tags and $obj->can('FREEZE') ) { + if ( $self->{PROPS}[P_ALLOW_TAGS] and $obj->can('FREEZE') ) { my $obj_class = ref $obj || $obj; $obj = bless $obj, $obj_class; my @results = $obj->FREEZE('JSON'); @@ -416,7 +387,7 @@ sub allow_bigint { return '("'.$obj_class.'")['.join(',', @results).']'; } - if ( $convert_blessed and $obj->can('TO_JSON') ) { + if ( $self->{PROPS}[P_CONVERT_BLESSED] and $obj->can('TO_JSON') ) { my $result = $obj->TO_JSON(); if ( defined $result and ref( $result ) ) { if ( refaddr( $obj ) eq refaddr( $result ) ) { @@ -430,10 +401,10 @@ sub allow_bigint { return $self->object_to_json( $result ); } - return "$obj" if ( $bignum and _is_bignum($obj) ); + return "$obj" if ( $self->{PROPS}[P_ALLOW_BIGNUM] and _is_bignum($obj) ); - if ($allow_blessed) { - return $self->blessed_to_json($obj) if ($as_nonblessed); # will be removed. + if ($self->{PROPS}[P_ALLOW_BLESSED]) { + return $self->blessed_to_json($obj) if ($self->{PROPS}[P_AS_NONBLESSED]); # will be removed. return 'null'; } encode_error( sprintf("encountered object '%s', but neither allow_blessed, convert_blessed nor allow_tags settings are enabled (or TO_JSON/FREEZE method missing)", $obj) @@ -454,19 +425,19 @@ sub allow_bigint { my @res; encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)") - if (++$depth > $max_depth); + if (++$self->{depth} > $self->{max_depth}); - my ($pre, $post) = $indent ? $self->_up_indent() : ('', ''); - my $del = ($space_before ? ' ' : '') . ':' . ($space_after ? ' ' : ''); + my ($pre, $post) = $self->{PROPS}[P_INDENT] ? $self->_up_indent() : ('', ''); + my $del = ($self->{PROPS}[P_SPACE_BEFORE] ? ' ' : '') . ':' . ($self->{PROPS}[P_SPACE_AFTER] ? ' ' : ''); - for my $k ( _sort( $obj ) ) { + for my $k ( $self->__sort( $obj ) ) { push @res, $self->string_to_json( $k ) . $del . ( ref $obj->{$k} ? $self->object_to_json( $obj->{$k} ) : $self->value_to_json( $obj->{$k} ) ); } - --$depth; - $self->_down_indent() if ($indent); + --$self->{depth}; + $self->_down_indent() if ($self->{PROPS}[P_INDENT]); return '{}' unless @res; return '{' . $pre . join( ",$pre", @res ) . $post . '}'; @@ -478,19 +449,20 @@ sub allow_bigint { my @res; encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)") - if (++$depth > $max_depth); + if (++$self->{depth} > $self->{max_depth}); - my ($pre, $post) = $indent ? $self->_up_indent() : ('', ''); + my ($pre, $post) = $self->{PROPS}[P_INDENT] ? $self->_up_indent() : ('', ''); for my $v (@$obj){ push @res, ref($v) ? $self->object_to_json($v) : $self->value_to_json($v); } - --$depth; - $self->_down_indent() if ($indent); + --$self->{depth}; + $self->_down_indent() if ($self->{PROPS}[P_INDENT]); return '[]' unless @res; - return '[' . $pre . join( ",$pre", @res ) . $post . ']'; + my $space = $pre eq '' && $self->{PROPS}[P_SPACE_AFTER] ? ' ' : ''; + return '[' . $pre . join( ",$space$pre", @res ) . $post . ']'; } sub _looks_like_number { @@ -579,20 +551,20 @@ sub allow_bigint { my ($self, $arg) = @_; $arg =~ s/(["\\\n\r\t\f\b])/$esc{$1}/g; - $arg =~ s/\//\\\//g if ($escape_slash); + $arg =~ s/\//\\\//g if ($self->{PROPS}[P_ESCAPE_SLASH]); # On ASCII platforms, matches [\x00-\x08\x0b\x0e-\x1f] $arg =~ s/([^\n\t\c?[:^cntrl:][:^ascii:]])/'\\u00' . unpack('H2', $1)/eg; - if ($ascii) { + if ($self->{PROPS}[P_ASCII]) { $arg = _encode_ascii($arg); } - if ($latin1) { + if ($self->{PROPS}[P_LATIN1]) { $arg = _encode_latin1($arg); } - if ($utf8) { + if ($self->{PROPS}[P_UTF8]) { utf8::encode($arg); } @@ -620,36 +592,30 @@ sub allow_bigint { } - sub _sort { + sub __sort { + my $self = shift; + my $keysort = $self->{keysort}; defined $keysort ? (sort $keysort (keys %{$_[0]})) : keys %{$_[0]}; } sub _up_indent { my $self = shift; - my $space = ' ' x $indent_length; + my $space = ' ' x $self->{indent_length}; my ($pre,$post) = ('',''); - $post = "\n" . $space x $indent_count; + $post = "\n" . $space x $self->{indent_count}; - $indent_count++; + $self->{indent_count}++; - $pre = "\n" . $space x $indent_count; + $pre = "\n" . $space x $self->{indent_count}; return ($pre,$post); } - sub _down_indent { $indent_count--; } - - - sub PP_encode_box { - { - depth => $depth, - indent_count => $indent_count, - }; - } + sub _down_indent { $_[0]->{indent_count}--; } } # Convert @@ -724,34 +690,6 @@ BEGIN { '/' => '/', ); - my $text; # json data - my $at; # offset - my $ch; # first character - my $len; # text length (changed according to UTF8 or NON UTF8) - # INTERNAL - my $depth; # nest counter - my $encoding; # json text encoding - my $is_valid_utf8; # temp variable - my $utf8_len; # utf8 byte length - # FLAGS - my $utf8; # must be utf8 - my $max_depth; # max nest number of objects and arrays - my $max_size; - my $relaxed; - my $cb_object; - my $cb_sk_object; - - my $F_HOOK; - - my $allow_bignum; # using Math::BigInt/BigFloat - my $singlequote; # loosely quoting - my $loose; # - my $allow_barekey; # bareKey - my $allow_tags; - - my $alt_true; - my $alt_false; - sub _detect_utf_encoding { my $text = shift; my @octets = unpack('C4', $text); @@ -765,25 +703,18 @@ BEGIN { } sub PP_decode_json { - my ($self, $want_offset); + my ($self, $text, $want_offset) = @_; - ($self, $text, $want_offset) = @_; - - ($at, $ch, $depth) = (0, '', 0); + @$self{qw/at ch depth/} = (0, '', 0); if ( !defined $text or ref $text ) { - decode_error("malformed JSON string, neither array, object, number, string or atom"); + $self->_decode_error("malformed JSON string, neither array, object, number, string or atom"); } my $props = $self->{PROPS}; - ($utf8, $relaxed, $loose, $allow_bignum, $allow_barekey, $singlequote, $allow_tags) - = @{$props}[P_UTF8, P_RELAXED, P_LOOSE .. P_ALLOW_SINGLEQUOTE, P_ALLOW_TAGS]; - - ($alt_true, $alt_false) = @$self{qw/true false/}; - - if ( $utf8 ) { - $encoding = _detect_utf_encoding($text); + if ( $self->{PROPS}[P_UTF8] ) { + my $encoding = _detect_utf_encoding($text); if ($encoding ne 'UTF-8' and $encoding ne 'unknown') { require Encode; Encode::from_to($text, $encoding, 'utf-8'); @@ -795,81 +726,84 @@ BEGIN { utf8::encode( $text ); } - $len = length $text; - - ($max_depth, $max_size, $cb_object, $cb_sk_object, $F_HOOK) - = @{$self}{qw/max_depth max_size cb_object cb_sk_object F_HOOK/}; + $self->{len} = length $text; + $self->{text} = $text; - if ($max_size > 1) { + if ($self->{max_size} > 1) { use bytes; my $bytes = length $text; - decode_error( + $self->_decode_error( sprintf("attempted decode of JSON text of %s bytes size, but max_size is set to %s" - , $bytes, $max_size), 1 - ) if ($bytes > $max_size); + , $bytes, $self->{max_size}), 1 + ) if ($bytes > $self->{max_size}); } - white(); # remove head white space + $self->_white(); # remove head white space - decode_error("malformed JSON string, neither array, object, number, string or atom") unless defined $ch; # Is there a first character for JSON structure? + $self->_decode_error("malformed JSON string, neither array, object, number, string or atom") unless defined $self->{ch}; # Is there a first character for JSON structure? - my $result = value(); + my $result = $self->_value(); if ( !$props->[ P_ALLOW_NONREF ] and !ref $result ) { - decode_error( + $self->_decode_error( 'JSON text must be an object or array (but found number, string, true, false or null,' . ' use allow_nonref to allow this)', 1); } - Carp::croak('something wrong.') if $len < $at; # we won't arrive here. + Carp::croak('something wrong.') if $self->{len} < $self->{at}; # we won't arrive here. - my $consumed = defined $ch ? $at - 1 : $at; # consumed JSON text length + my $consumed = defined $self->{ch} ? $self->{at} - 1 : $self->{at}; # consumed JSON text length - white(); # remove tail white space + $self->_white(); # remove tail white space return ( $result, $consumed ) if $want_offset; # all right if decode_prefix - decode_error("garbage after JSON object") if defined $ch; + $self->_decode_error("garbage after JSON object") if defined $self->{ch}; $result; } - sub next_chr { - return $ch = undef if($at >= $len); - $ch = substr($text, $at++, 1); + sub _next_chr { + my $self = shift; + return $self->{ch} = undef if($self->{at} >= $self->{len}); + $self->{ch} = substr($self->{text}, $self->{at}++, 1); } - sub value { - white(); + sub _value { + my $self = shift; + $self->_white(); + my $ch = $self->{ch}; return if(!defined $ch); - return object() if($ch eq '{'); - return array() if($ch eq '['); - return tag() if($ch eq '('); - return string() if($ch eq '"' or ($singlequote and $ch eq "'")); - return number() if($ch =~ /[0-9]/ or $ch eq '-'); - return word(); + return $self->_object() if($ch eq '{'); + return $self->_array() if($ch eq '['); + return $self->_tag() if($ch eq '('); + return $self->_string() if($ch eq '"' or ($self->{PROPS}[P_ALLOW_SINGLEQUOTE] and $ch eq "'")); + return $self->_number() if($ch =~ /[0-9]/ or $ch eq '-'); + return $self->_word(); } - sub string { + sub _string { + my $self = shift; my $utf16; my $is_utf8; - ($is_valid_utf8, $utf8_len) = ('', 0); + my $utf8_len = 0; my $s = ''; # basically UTF8 flag on - if($ch eq '"' or ($singlequote and $ch eq "'")){ + my $ch = $self->{ch}; + if($ch eq '"' or ($self->{PROPS}[P_ALLOW_SINGLEQUOTE] and $ch eq "'")){ my $boundChar = $ch; - OUTER: while( defined(next_chr()) ){ + OUTER: while( defined($ch = $self->_next_chr()) ){ if($ch eq $boundChar){ - next_chr(); + $self->_next_chr(); if ($utf16) { - decode_error("missing low surrogate character in surrogate pair"); + $self->_decode_error("missing low surrogate character in surrogate pair"); } utf8::decode($s) if($is_utf8); @@ -877,7 +811,7 @@ BEGIN { return $s; } elsif($ch eq '\\'){ - next_chr(); + $ch = $self->_next_chr(); if(exists $escapes{$ch}){ $s .= $escapes{$ch}; } @@ -885,7 +819,7 @@ BEGIN { my $u = ''; for(1..4){ - $ch = next_chr(); + $ch = $self->_next_chr(); last OUTER if($ch !~ /[0-9a-fA-F]/); $u .= $ch; } @@ -897,7 +831,7 @@ BEGIN { # U+DC00 - U+DFFF elsif ($u =~ /^[dD][c-fC-F][0-9a-fA-F]{2}/) { # UTF-16 low surrogate? unless (defined $utf16) { - decode_error("missing high surrogate character in surrogate pair"); + $self->_decode_error("missing high surrogate character in surrogate pair"); } $is_utf8 = 1; $s .= _decode_surrogates($utf16, $u) || next; @@ -905,7 +839,7 @@ BEGIN { } else { if (defined $utf16) { - decode_error("surrogate pair expected"); + $self->_decode_error("surrogate pair expected"); } my $hex = hex( $u ); @@ -920,9 +854,9 @@ BEGIN { } else{ - unless ($loose) { - $at -= 2; - decode_error('illegal backslash escape sequence in string'); + unless ($self->{PROPS}[P_LOOSE]) { + $self->{at} -= 2; + $self->_decode_error('illegal backslash escape sequence in string'); } $s .= $ch; } @@ -930,22 +864,22 @@ BEGIN { else{ if ( $ch =~ /[[:^ascii:]]/ ) { - unless( $ch = is_valid_utf8($ch) ) { - $at -= 1; - decode_error("malformed UTF-8 character in JSON string"); + unless( $ch = $self->_is_valid_utf8($ch, \$utf8_len) ) { + $self->{at} -= 1; + $self->_decode_error("malformed UTF-8 character in JSON string"); } else { - $at += $utf8_len - 1; + $self->{at} += $utf8_len - 1; } $is_utf8 = 1; } - if (!$loose) { + if (!$self->{PROPS}[P_LOOSE]) { if ($ch =~ $invalid_char_re) { # '/' ok - if (!$relaxed or $ch ne "\t") { - $at--; - decode_error(sprintf "invalid character 0x%X" + if (!$self->{PROPS}[P_RELAXED] or $ch ne "\t") { + $self->{at}--; + $self->_decode_error(sprintf "invalid character 0x%X" . " encountered while parsing JSON string", ord $ch); } @@ -957,51 +891,53 @@ BEGIN { } } - decode_error("unexpected end of string while parsing JSON string"); + $self->_decode_error("unexpected end of string while parsing JSON string"); } - sub white { + sub _white { + my $self = shift; + my $ch = $self->{ch}; while( defined $ch ){ if($ch eq '' or $ch =~ /\A[ \t\r\n]\z/){ - next_chr(); + $ch = $self->_next_chr(); } - elsif($relaxed and $ch eq '/'){ - next_chr(); + elsif($self->{PROPS}[P_RELAXED] and $ch eq '/'){ + $ch = $self->_next_chr(); if(defined $ch and $ch eq '/'){ - 1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r"); + 1 while(defined($ch = $self->_next_chr()) and $ch ne "\n" and $ch ne "\r"); } elsif(defined $ch and $ch eq '*'){ - next_chr(); + $ch = $self->_next_chr(); while(1){ if(defined $ch){ if($ch eq '*'){ - if(defined(next_chr()) and $ch eq '/'){ - next_chr(); + if(defined($ch = $self->_next_chr()) and $ch eq '/'){ + $ch = $self->_next_chr(); last; } } else{ - next_chr(); + $ch = $self->_next_chr(); } } else{ - decode_error("Unterminated comment"); + $self->_decode_error("Unterminated comment"); } } next; } else{ - $at--; - decode_error("malformed JSON string, neither array, object, number, string or atom"); + $self->{at}--; + $self->_decode_error("malformed JSON string, neither array, object, number, string or atom"); } } else{ - if ($relaxed and $ch eq '#') { # correctly? - pos($text) = $at; - $text =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g; - $at = pos($text); - next_chr; + if ($self->{PROPS}[P_RELAXED] and $ch eq '#') { # correctly? + pos($self->{text}) = $self->{at}; + $self->{text} =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g; + $self->{at} = pos($self->{text}); + $ch = $self->_next_chr; next; } @@ -1011,33 +947,36 @@ BEGIN { } - sub array { + sub _array { + my $self = shift; my $a = $_[0] || []; # you can use this code to use another array ref object. - decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)') - if (++$depth > $max_depth); + $self->_decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)') + if (++$self->{depth} > $self->{max_depth}); - next_chr(); - white(); + $self->_next_chr(); + $self->_white(); + my $ch = $self->{ch}; if(defined $ch and $ch eq ']'){ - --$depth; - next_chr(); + --$self->{depth}; + $self->_next_chr(); return $a; } else { while(defined($ch)){ - push @$a, value(); + push @$a, $self->_value(); - white(); + $self->_white(); + $ch = $self->{ch}; if (!defined $ch) { last; } if($ch eq ']'){ - --$depth; - next_chr(); + --$self->{depth}; + $self->_next_chr(); return $a; } @@ -1045,90 +984,97 @@ BEGIN { last; } - next_chr(); - white(); + $self->_next_chr(); + $self->_white(); - if ($relaxed and $ch eq ']') { - --$depth; - next_chr(); + $ch = $self->{ch}; + if ($self->{PROPS}[P_RELAXED] and $ch eq ']') { + --$self->{depth}; + $self->_next_chr(); return $a; } } } - $at-- if defined $ch and $ch ne ''; - decode_error(", or ] expected while parsing array"); + $self->{at}-- if defined $ch and $ch ne ''; + $self->_decode_error(", or ] expected while parsing array"); } - sub tag { - decode_error('malformed JSON string, neither array, object, number, string or atom') unless $allow_tags; + sub _tag { + my $self = shift; + $self->_decode_error('malformed JSON string, neither array, object, number, string or atom') unless $self->{PROPS}[P_ALLOW_TAGS]; - next_chr(); - white(); + $self->_next_chr(); + $self->_white(); - my $tag = value(); + my $tag = $self->_value(); return unless defined $tag; - decode_error('malformed JSON string, (tag) must be a string') if ref $tag; + $self->_decode_error('malformed JSON string, (tag) must be a string') if ref $tag; - white(); + $self->_white(); + my $ch = $self->{ch}; if (!defined $ch or $ch ne ')') { - decode_error(') expected after tag'); + $self->_decode_error(') expected after tag'); } - next_chr(); - white(); + $self->_next_chr(); + $self->_white(); - my $val = value(); + my $val = $self->_value(); return unless defined $val; - decode_error('malformed JSON string, tag value must be an array') unless ref $val eq 'ARRAY'; + $self->_decode_error('malformed JSON string, tag value must be an array') unless ref $val eq 'ARRAY'; if (!eval { $tag->can('THAW') }) { - decode_error('cannot decode perl-object (package does not exist)') if $@; - decode_error('cannot decode perl-object (package does not have a THAW method)'); + $self->_decode_error('cannot decode perl-object (package does not exist)') if $@; + $self->_decode_error('cannot decode perl-object (package does not have a THAW method)'); } $tag->THAW('JSON', @$val); } - sub object { + sub _object { + my $self = shift; my $o = $_[0] || {}; # you can use this code to use another hash ref object. my $k; - decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)') - if (++$depth > $max_depth); - next_chr(); - white(); + $self->_decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)') + if (++$self->{depth} > $self->{max_depth}); + $self->_next_chr(); + $self->_white(); + my $ch = $self->{ch}; if(defined $ch and $ch eq '}'){ - --$depth; - next_chr(); - if ($F_HOOK) { - return _json_object_hook($o); + --$self->{depth}; + $self->_next_chr(); + if ($self->{F_HOOK}) { + return $self->__json_object_hook($o); } return $o; } else { while (defined $ch) { - $k = ($allow_barekey and $ch ne '"' and $ch ne "'") ? bareKey() : string(); - white(); + $k = ($self->{PROPS}[P_ALLOW_BAREKEY] and $ch ne '"' and $ch ne "'") ? $self->_bareKey() : $self->_string(); + $self->_white(); + $ch = $self->{ch}; if(!defined $ch or $ch ne ':'){ - $at--; - decode_error("':' expected"); + $self->{at}--; + $self->_decode_error("':' expected"); } - next_chr(); - $o->{$k} = value(); - white(); + $self->_next_chr(); + $o->{$k} = $self->_value(); + $self->_white(); + $ch = $self->{ch}; last if (!defined $ch); if($ch eq '}'){ - --$depth; - next_chr(); - if ($F_HOOK) { - return _json_object_hook($o); + --$self->{depth}; + $self->_next_chr(); + if ($self->{F_HOOK}) { + return $self->__json_object_hook($o); } return $o; } @@ -1137,14 +1083,15 @@ BEGIN { last; } - next_chr(); - white(); + $self->_next_chr(); + $self->_white(); - if ($relaxed and $ch eq '}') { - --$depth; - next_chr(); - if ($F_HOOK) { - return _json_object_hook($o); + $ch = $self->{ch}; + if ($self->{PROPS}[P_RELAXED] and $ch eq '}') { + --$self->{depth}; + $self->_next_chr(); + if ($self->{F_HOOK}) { + return $self->__json_object_hook($o); } return $o; } @@ -1153,94 +1100,99 @@ BEGIN { } - $at-- if defined $ch and $ch ne ''; - decode_error(", or } expected while parsing object/hash"); + $self->{at}-- if defined $ch and $ch ne ''; + $self->_decode_error(", or } expected while parsing object/hash"); } - sub bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition + sub _bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition + my $self = shift; my $key; + my $ch = $self->{ch}; while($ch =~ /[\$\w[:^ascii:]]/){ $key .= $ch; - next_chr(); + $ch = $self->_next_chr(); } return $key; } - sub word { - my $word = substr($text,$at-1,4); + sub _word { + my $self = shift; + my $word = substr($self->{text},$self->{at}-1,4); if($word eq 'true'){ - $at += 3; - next_chr; - return defined $alt_true ? $alt_true : $JSON::PP::true; + $self->{at} += 3; + $self->_next_chr; + return defined $self->{true} ? $self->{true} : $JSON::PP::true; } elsif($word eq 'null'){ - $at += 3; - next_chr; + $self->{at} += 3; + $self->_next_chr; return undef; } elsif($word eq 'fals'){ - $at += 3; - if(substr($text,$at,1) eq 'e'){ - $at++; - next_chr; - return defined $alt_false ? $alt_false : $JSON::PP::false; + $self->{at} += 3; + if(substr($self->{text},$self->{at},1) eq 'e'){ + $self->{at}++; + $self->_next_chr; + return defined $self->{false} ? $self->{false} : $JSON::PP::false; } } - $at--; # for decode_error report + $self->{at}--; # for decode_error report - decode_error("'null' expected") if ($word =~ /^n/); - decode_error("'true' expected") if ($word =~ /^t/); - decode_error("'false' expected") if ($word =~ /^f/); - decode_error("malformed JSON string, neither array, object, number, string or atom"); + $self->_decode_error("'null' expected") if ($word =~ /^n/); + $self->_decode_error("'true' expected") if ($word =~ /^t/); + $self->_decode_error("'false' expected") if ($word =~ /^f/); + $self->_decode_error("malformed JSON string, neither array, object, number, string or atom"); } - sub number { + sub _number { + my $self = shift; my $n = ''; my $v; my $is_dec; my $is_exp; + my $ch = $self->{ch}; if($ch eq '-'){ $n = '-'; - next_chr; + $ch = $self->_next_chr; if (!defined $ch or $ch !~ /\d/) { - decode_error("malformed number (no digits after initial minus)"); + $self->_decode_error("malformed number (no digits after initial minus)"); } } # According to RFC4627, hex or oct digits are invalid. if($ch eq '0'){ - my $peek = substr($text,$at,1); + my $peek = substr($self->{text},$self->{at},1); if($peek =~ /^[0-9a-dfA-DF]/){ # e may be valid (exponential) - decode_error("malformed number (leading zero must not be followed by another digit)"); + $self->_decode_error("malformed number (leading zero must not be followed by another digit)"); } $n .= $ch; - next_chr; + $ch = $self->_next_chr; } while(defined $ch and $ch =~ /\d/){ $n .= $ch; - next_chr; + $ch = $self->_next_chr; } if(defined $ch and $ch eq '.'){ $n .= '.'; $is_dec = 1; - next_chr; + $ch = $self->_next_chr; if (!defined $ch or $ch !~ /\d/) { - decode_error("malformed number (no digits after decimal point)"); + $self->_decode_error("malformed number (no digits after decimal point)"); } else { $n .= $ch; } - while(defined(next_chr) and $ch =~ /\d/){ + while(defined($ch = $self->_next_chr) and $ch =~ /\d/){ $n .= $ch; } } @@ -1248,13 +1200,13 @@ BEGIN { if(defined $ch and ($ch eq 'e' or $ch eq 'E')){ $n .= $ch; $is_exp = 1; - next_chr; + $ch = $self->_next_chr; if(defined($ch) and ($ch eq '+' or $ch eq '-')){ $n .= $ch; - next_chr; + $ch = $self->_next_chr; if (!defined $ch or $ch =~ /\D/) { - decode_error("malformed number (no digits after exp sign)"); + $self->_decode_error("malformed number (no digits after exp sign)"); } $n .= $ch; } @@ -1262,10 +1214,10 @@ BEGIN { $n .= $ch; } else { - decode_error("malformed number (no digits after exp sign)"); + $self->_decode_error("malformed number (no digits after exp sign)"); } - while(defined(next_chr) and $ch =~ /\d/){ + while(defined($ch = $self->_next_chr) and $ch =~ /\d/){ $n .= $ch; } @@ -1274,13 +1226,13 @@ BEGIN { $v .= $n; if ($is_dec or $is_exp) { - if ($allow_bignum) { + if ($self->{PROPS}[P_ALLOW_BIGNUM]) { require Math::BigFloat; return Math::BigFloat->new($v); } } else { if (length $v > $max_intsize) { - if ($allow_bignum) { # from Adam Sussman + if ($self->{PROPS}[P_ALLOW_BIGNUM]) { # from Adam Sussman require Math::BigInt; return Math::BigInt->new($v); } @@ -1302,13 +1254,14 @@ BEGIN { utf8::encode($max_unicode_length); $max_unicode_length = length $max_unicode_length; - sub is_valid_utf8 { + sub _is_valid_utf8 { + my ($self, $ch, $utf8_len_r) = @_; # Returns undef (setting $utf8_len to 0) unless the next bytes in $text # comprise a well-formed UTF-8 encoded character, in which case, # return those bytes, setting $utf8_len to their count. - my $start_point = substr($text, $at - 1); + my $start_point = substr($self->{text}, $self->{at} - 1); # Look no further than the maximum number of bytes in a single # character @@ -1329,8 +1282,8 @@ BEGIN { # and return those bytes. $copy = substr($copy, 0, 1); utf8::encode($copy); - $utf8_len = length $copy; - return substr($start_point, 0, $utf8_len); + $$utf8_len_r = length $copy; + return substr($start_point, 0, $$utf8_len_r); } # If it didn't work, it could be that there is a full legal character @@ -1340,15 +1293,16 @@ BEGIN { } # Failed to find a legal UTF-8 character. - $utf8_len = 0; + $$utf8_len_r = 0; return; } - sub decode_error { + sub _decode_error { + my $self = shift; my $error = shift; my $no_rep = shift; - my $str = defined $text ? substr($text, $at) : ''; + my $str = defined $self->{text} ? substr($self->{text}, $self->{at}) : ''; my $mess = ''; my $type = 'U*'; @@ -1374,18 +1328,19 @@ BEGIN { } Carp::croak ( - $no_rep ? "$error" : "$error, at character offset $at (before \"$mess\")" + $no_rep ? "$error" : "$error, at character offset $self->{at} (before \"$mess\")" ); } - sub _json_object_hook { + sub __json_object_hook { + my $self = shift; my $o = $_[0]; my @ks = keys %{$o}; - if ( $cb_sk_object and @ks == 1 and exists $cb_sk_object->{ $ks[0] } and ref $cb_sk_object->{ $ks[0] } ) { - my @val = $cb_sk_object->{ $ks[0] }->( $o->{$ks[0]} ); + if ( $self->{cb_sk_object} and @ks == 1 and exists $self->{cb_sk_object}{ $ks[0] } and ref $self->{cb_sk_object}{ $ks[0] } ) { + my @val = $self->{cb_sk_object}{ $ks[0] }->( $o->{$ks[0]} ); if (@val == 0) { return $o; } @@ -1397,7 +1352,7 @@ BEGIN { } } - my @val = $cb_object->($o) if ($cb_object); + my @val = $self->{cb_object}->($o) if ($self->{cb_object}); if (@val == 0) { return $o; } @@ -1409,19 +1364,6 @@ BEGIN { } } - - sub PP_decode_box { - { - text => $text, - at => $at, - ch => $ch, - len => $len, - depth => $depth, - encoding => $encoding, - is_valid_utf8 => $is_valid_utf8, - }; - } - } # PARSE @@ -1849,7 +1791,7 @@ and are also used to represent JSON C and C in Perl strings. On perl 5.36 and above, will also return true when given one of perl's standard boolean values, such as the result of a comparison. -See L, below, for more information on how JSON values are mapped to +See L, below, for more information on how JSON values are mapped to Perl. =head1 OBJECT-ORIENTED INTERFACE @@ -2136,7 +2078,7 @@ This setting has currently no effect on tied hashes. $enabled = $json->get_allow_nonref -Unlike other boolean options, this opotion is enabled by default beginning +Unlike other boolean options, this option is enabled by default beginning with version C<4.0>. If C<$enable> is true (or missing), then the C method can convert a @@ -2508,7 +2450,7 @@ objects into JSON numbers. print $json->encode($bigfloat); # => 2.000000000000000000000000001 -See also L. +See also L. =head2 loose @@ -2575,7 +2517,7 @@ then the argument will be passed to Perl's C built-in function. As the sorting is done in the JSON::PP scope, you usually need to prepend C to the subroutine name, and the special variables -C<$a> and C<$b> used in the subrontine used by C function. +C<$a> and C<$b> used in the subroutine used by C function. Example: @@ -2940,7 +2882,7 @@ argument being the object to serialise, and the second argument being the constant string C to distinguish it from other serialisers. The C method can return any number of values (i.e. zero or -more). These values and the paclkage/classname of the object will then be +more). These values and the package/classname of the object will then be encoded as a tagged JSON value in the following format: ("classname")[FREEZE return values...] diff --git a/src/main/perl/lib/JSON/PP/Boolean.pm b/src/main/perl/lib/JSON/PP/Boolean.pm index 146446e93..000a3586a 100644 --- a/src/main/perl/lib/JSON/PP/Boolean.pm +++ b/src/main/perl/lib/JSON/PP/Boolean.pm @@ -11,7 +11,7 @@ overload::import('overload', fallback => 1, ); -our $VERSION = '4.16'; +our $VERSION = '4.18'; 1; diff --git a/src/main/perl/lib/Pod/perl.pod b/src/main/perl/lib/Pod/perl.pod index eee74c0a8..d13b04ced 100644 --- a/src/main/perl/lib/Pod/perl.pod +++ b/src/main/perl/lib/Pod/perl.pod @@ -182,6 +182,7 @@ aux h2ph h2xs perlbug pl2pm pod2html pod2man splain xsubpp perlhist Perl history records perldelta Perl changes since previous version + perl5440delta Perl changes in version 5.44.0 perl5422delta Perl changes in version 5.42.2 perl5421delta Perl changes in version 5.42.1 perl5420delta Perl changes in version 5.42.0 diff --git a/src/main/perl/lib/Pod/perl5440delta.pod b/src/main/perl/lib/Pod/perl5440delta.pod new file mode 100644 index 000000000..45eacdf6b --- /dev/null +++ b/src/main/perl/lib/Pod/perl5440delta.pod @@ -0,0 +1,1393 @@ +=encoding utf8 + +=head1 NAME + +perl5440delta - what is new for perl v5.44.0 + +=head1 DESCRIPTION + +This document describes differences between the 5.42.0 release and the 5.44.0 +release. + +=head1 Core Enhancements + +=head2 Named Parameters in Signatures + +This adds a major new ability to subroutine signatures, allowing callers +to pass parameters by name/value pairs rather than by position. + + sub f ($x, $y, :$alpha, :$beta = undef) { ... } + + f( 123, 456, alpha => 789 ); + +Originally specified in +L. + +This feature is currently considered B, and is described in +further detail in L. + +=head2 Multi-variable C can now use aliased references + +Perl version 5.22 introduced reference aliases, allowing a C loop +iteration variable to create new aliases to references. Perl version 5.36 +introduced C loops with multiple variables, consuming more than one +input list item on each iteration. New in this version, the two features may +now be used together, allowing multiple iteration variables where any of them +are permitted to be reference aliases. + + use v5.44; + use feature qw( refaliasing declared_refs ); + + my %hash = ( + one => [1], + two => [2, 2], + ); + + foreach my ( $key, \@items ) ( %hash ) { + say "The $key array contains: @items"; + } + +Currently both the C and C features remain +B. + +=head2 Enhanced operation of regular expression patterns under /xx + +Experimentally, the C pattern modifier can allow bracketed +character classes (I, C<[a-zA-Z]> to extend across multiple lines +and to contain comments, and to warn you of potential cases where a +portion of a pattern inadvertently has been treated as a comment instead +of what you intended. This behavior is enabled by S>. See Lx and Exx>. + +=head2 Unicode 17.0 is supported + +See L. + +=head2 New source of entropy for PRNG seeding + +Perl now uses the C system call to fetch random bytes suitable +for seeding the internal PRNG. Previously Perl would read raw bytes from the +F device. Perl now seeds itself in this order (and falls through +upon failure): + +=over + +=item 1. + +C on systems that support this call (Linux, BSD, MacOS) + +=item 2. + +F on systems that have it + +=item 3. + +Hash of internal state variables: Unix time, process ID, and pointer value + +=back + +Note that the internal PRNG is still unsuitable for security applications. +See L for a discussion of security. + +=head1 Security + +=head2 CVE-2026-8376 - Buffer overflow in Perl_study_chunk + +Perl_study_chunk in regcomp_study.c checked the size of the joined substring +buffer in characters rather than bytes. On 32-bit builds, this can lead to +an integer overflow of the size of the buffer leading to out-of-bounds writes. + +=head2 CVE-2026-57432 - Buffer overflow in S_measure_struct + +If you call C or C to operate on a structure whose computed size +is too large to fit in memory, an integer overflow could happen that would +result in a buffer overflow. This usually happens as a result of embedding a +large number as the repeat count for an item. + +=head2 CVE-2026-13221 - Regex trie 16-bit field overflow + +The trie optimization in the regex engine could overflow in an alternation with more than ~65k branches. This could cause both false positives and false negatives on such regular expressions. + +=head1 Incompatible Changes + +=head2 Unicode rules are now fully enforced on identifier and regular expression group names. + +Before Unicode, Perl accepted any C<\w> character in an identifier or other +name, except the first character couldn't be a digit. Later, Unicode +created two properties that described this. Even later, they found +those properties to be insufficient, and created two new similar +properties. These are the ones that perl has intended to use since: +C<\p{XID_Start}> and C<\p{XID_Continue}>. (The C stands for +"eXtended" and indicates these are the more modern versions.) + +(And even later, long after Perl identifier rules were formed using +the above properties, Unicode added recommendations to further restrict +legal identifier names. These were added to counter cases where, for +example, programmers snuck code past reviewers using characters that +look like other ones. The two properties are C and +C. See L. Perl +currently doesn't do anything with these, except to furnish you the +ability to use them in regular expressions.) + +We soon discovered that there were 14 characters that match C +and C that don't also match C<\w>. To avoid breaking code +that had long relied on C<\w>, we chose to not add those to the list of +acceptable identifier characters. + +It turns out that there are about 160 characters that match C<\w> but +not the Unicode C properties. Thus they are illegal according to +Unicode. Those are now explicitly forbidden in both Perl identifiers +and regular expression group names. Previously, it was likely that +their use in identifiers wouldn't work anyway; they could be accepted +initially as legal, but other code would later reject them, but with a +message that had nothing to do with the underlying problem. However +group names in regular expression patterns could contain illegal +continuation characters and have a higher probability of not being +caught. That is now changed. + +Only programs that do L|utf8> can be affected, and then only +characters that appear in the 2nd or later positions of the name. The +characters that an identifier name can begin with are unchanged. + +130 of the now unacceptable characters are 5 sets of 26 Latin letters +that are enclosed by some shape, such as CIRCLED LATIN CAPITAL LETTER N. +Another 8 are generic modifiers that add shapes around other characters; +5 are modifiers to Cyrillic numbers; and 16 are Arabic ligatures and +isolated forms. The other two are GREEK YPOGEGRAMMENI and VERTICAL +TILDE. + +=head1 Deprecations + +=over 4 + +=item * + +Deprecated since 5.12, using C to jump into the body of a loop or +other block construct from outside is no longer permitted. +[L] + +=item * + +C has new restrictions + +Using an unescaped C<#> or literal vertical space is now deprecated in a +regular expression bracketed character class that is compiled with the +C modifier. These still work, but deprecation warnings will be +generated unless turned off or the constructs are cured as follows. + +=over + +=item * + +Escape a C<#> by preceding it with a backslash, like in + + m/ [ % \# ( ) ] /xx + +=item * + +Use constructs like C<\n> instead of literal vertical space. + +=back + +=back + +=head1 Performance Enhancements + +=over 4 + +=item * + +Simple (non-overflowing) addition (C<+>), subtraction (C<->) and +multiplication (C<*>) of integers are slightly sped up, as long as +sufficient underlying C compiler support is available. + +=item * + +Populating a hash from a list of key/value pairs when the keys are constant +string operands known at compile time is commonly now faster. [L] + +=item * + +Processing of signatures at the start of a subroutine under the C +feature is now more efficient at runtime. + +=back + +=head1 Modules and Pragmata + +=head2 Updated Modules and Pragmata + +=over 4 + +=item * + +L has been upgraded from version 3.04 to 3.12. + +This fixes CVE-2026-9538, CVE-2026-42496, and CVE-2026-42497. + +=item * + +L has been upgraded from version 0.36 to 0.37. + +=item * + +L has been upgraded from version 1.89 to 1.92. + +=item * + +L has been upgraded from version 1.007 to 1.012. + +=item * + +L has been upgraded from version 1.85 to 1.89. + +=item * + +L has been upgraded from version 1.50 to 1.51. + +=item * + +L has been upgraded from version 2.213 to 2.218. + +=item * + +L has been upgraded from version 2.213 to 2.222. + +=item * + +L has been upgraded from version 0.38 to 0.39. + +=item * + +L has been upgraded from version 2.150010 to 2.150013. + +=item * + +L has been upgraded from version 2.143 to 2.145. + +=item * + +L has been upgraded from version 1.859 to 1.860. + +=item * + +L has been upgraded from version 3.21 to 3.24. + +=item * + +L has been upgraded from version 1.11 to 1.12. + +=item * + +L has been upgraded from version 1.38 to 1.39. + +=item * + +L has been upgraded from version 0.035 to 0.036. + +=item * + +L has been upgraded from version 0.280242 to 0.280243. + +=item * + +L has been upgraded from version 7.76 to 7.78. + +=item * + +L has been upgraded from version 1.14 to 1.15. + +=item * + +L has been upgraded from version 3.57 to 3.63. + +=item * + +L has been upgraded from version 3.57 to 3.63. + +=item * + +L has been upgraded from version 1.97 to 2.02. + +=item * + +L has been upgraded from version 2.41 to 2.43. + +=item * + +L has been upgraded from version 1.04 to 1.08. + +=item * + +L has been upgraded from version 1.42 to 1.44. + +=item * + +L has been upgraded from version 3.94 to 3.95. + +=item * + +L has been upgraded from version 1.14 to 1.15. + +=item * + +L has been upgraded from version 0.2311 to 0.2312. + +=item * + +L has been upgraded from version 0.96 to 0.97. + +=item * + +L has been upgraded from version 1.64 to 1.65. + +=item * + +L has been upgraded from version 1.14 to 1.15. + +=item * + +L has been upgraded from version 0.090 to 0.096. + +This fixes CVE-2026-7010 and CVE-2026-7017. + +=item * + +L has been upgraded from version 1.55 to 1.56. + +=item * + +L has been upgraded from version 2.213 to 2.223. + +This fixes CVE-2025-15649, CVE-2026-48961, CVE-2026-48962, and CVE-2026-48959. + +=item * + +L has been upgraded from version 0.43 to 0.44. + +=item * + +L has been upgraded from version 2.005002 to 2.005003. + +=item * + +L has been upgraded from version 5.20250702 to 5.20260708. + +=item * + +L has been upgraded from version 1.000038 to 1.000039. + +=item * + +L has been upgraded from version 1.29 to 1.30. + +=item * + +L has been upgraded from version 2.76 to 2.77. + +=item * + +L has been upgraded from version 1.69 to 1.71. + +=item * + +L has been upgraded from version 0.02 to 0.03. + +=item * + +L has been upgraded from version 0.19 to 0.21. + +=item * + +L has been upgraded from version 1.35 to 1.36. + +=item * + +L has been upgraded from version 3.45 to 3.48. + +=item * + +L has been upgraded from version 2.23 to 2.26. + +=item * + +L has been upgraded from version 1.68_01 to 1.70. + +=item * + +L has been upgraded from version 1.02 to 1.03. + +=item * + +L has been upgraded from version 1.28 to 1.29. + +=item * + +L has been upgraded from version 2.038 to 2.041. + +This fixes CVE-2026-12087. + +=item * + +L has been upgraded from version 3.37 to 3.41. + +This fixes CVE-2026-57433. + +=item * + +L has been upgraded from version 0.024 to 0.028. + +=item * + +L has been upgraded from version 3.50 to 3.52. + +=item * + +L has been upgraded from version 1.302210 to 1.302219. + +=item * + +L has been upgraded from version 2.06 to 2.07. + +=item * + +L has been upgraded from version 2.43 to 2.45. + +=item * + +L has been upgraded from version 1.70 to 1.73. + +=item * + +L has been upgraded from version 1.9778 to 1.9780. + +=item * + +L has been upgraded from version 1.36 to 1.41. + +=item * + +L has been upgraded from version 0.81 to 0.83. + +=item * + +L has been upgraded from version 1.17 to 1.18. + +=item * + +L has been upgraded from version 1.27 to 1.29. + +=item * + +L has been upgraded from version 0.9933 to 0.9934. + +=item * + +L has been upgraded from version 1.74 to 1.78. + +=item * + +L has been upgraded from version 1.43 to 1.50. + +=item * + +L has been upgraded from version 0.20 to 0.22. + +=back + +=head1 Documentation + +=head2 Changes to Existing Documentation + +We have attempted to update the documentation to reflect the changes +listed in this document. If you find any we have missed, open an issue +at L. + +Additionally, the following selected changes have been made: + +=head3 L + +=over 4 + +=item * + +Auto-generation of this document now includes the line number of the source +code, as well as its documentation. + +=item * + +It now contains information about how to find what release of +Perl first contained an API element. + +=back + +=head3 L + +=over 4 + +=item * + +New entry for "New object system and C syntax". + +=back + +=head3 L + +=over 4 + +=item * + +The reference manual for writing Perl XS code has been completely rewritten and +modernized. It is about twice the size of the old file, and promotes more +modern XS syntax, such as ANSI signatures. + +=back + +=head1 Diagnostics + +The following additions or changes have been made to diagnostic output, +including warnings and fatal error messages. For the complete list of +diagnostic messages, see L. + +=head2 Changes to Existing Diagnostics + +=over 4 + +=item * + +L + +This warning was issued in the reverse order (right-to-left) when both +operands of a binary operator are uninitialized values. This is now +fixed to be consistent with evaluation order of operands. + +=item * + +Certain diagnostics about byte sequences that are supposed to comprise a +UTF-8 encoded character, but that are invalid in some way, now don't +include bytes irrelevant to that determination. An example is + +=over + +=item old message + +Malformed UTF-8 character: C<\xc1\x27> (any UTF-8 sequence that starts with +C<\xc1> is overlong which can and should be represented with a different, +shorter sequence) + +=item new message + +Malformed UTF-8 character: C<\xc1> (any UTF-8 sequence that starts with +C<\xc1> is overlong which can and should be represented with a different, +shorter sequence) + +=back + +In this case the C<\xc1> is all that is needed to make the sequence +invalid. Whatever comes after it is irrelevant (in this case, C<\x27>), +and including it in the message might lead the reader to think that it +somehow does matter. + +=item * + +The error C has been changed +to C. + +=item * + +Variables whose name started with C<^_> were incorrectly shown in +diagnostics with a literal C (which is an invisible ASCII +character) in their name. + +The names of variables whose names begin with a caret and are longer +than two characters are now wrapped in braces, just as they have to be +in the source code. + +Therefore, using an undefined C<${^_FOO}> will now correctly warn with +C, instead of the earlier C (with a literal C after the dollar +sign). + +[L] + +=item * + +Calling the C method on a package with no C method now +produces a regular warning rather than a deprecation warning or error. + +Since Perl 5.39.1, calling C with arguments on a package without +such a method has triggered a deprecation warning. In Perl 5.43.6, this +deprecation was promoted into an error. This broke a significant amount +of code while providing very little advantage over the warning. This +fatal error has been converted back to a warning, with its deprecation +status removed. There are no longer any plans to make this fatal in the +future. The category for this warning is C and it is +enabled by default. + +=back + +=head2 New Diagnostics + +=head3 New Errors + +=over 4 + +=item * + +L + +(F) A C, C or C keyword was used with the exception variable in +a C block: + + try { ... } + catch (my $e) { ... } + # or catch (our $e) { ... } + # or catch (state $e) { ... } + +This is not valid syntax. C takes a bare variable name, which is +automatically lexically declared. +[L] + +=item * + +L + +(F) You have used C or C in an attempt to jump into +the body of a loop or other block construct from the outside. As of Perl 5.44, +this throws an exception. + +=item * + +L<\x{%X} is a \w char that isn't valid in a name "%s" +|perldiag/\x{%X} is a \w char that isn't valid in a name "%s"> + +In most cases where this message now appears, an error would have +occurred anyway, but the text would not have been helpful in finding the +problem. + +=back + +=head3 New Warnings + +=over 4 + +=item * + +L + +(W qw) qw() lists contain items separated by whitespace; contrary to +what some might expect, backslash characters cannot be used to "protect" +whitespace from being split, but are instead treated as literal data. + +Note that this warning is I emitted when the backslash is followed +by actual whitespace (that C splits on). + +=back + +=head1 Configuration and Compilation + +=over 4 + +=item * + +C23 F<< >> and associated macros are now used if available. + +=item * + +It is now possible to pass to F the values dealing with POSIX +locale categories, overriding its automatic calculation of these. This +enables cross-compilation to work. The easiest way to do this is to +extract the C program that does the calculation from F and +then run it on the target machine, and then pass the values it outputs +to F on the other machine. F has examples. +[L] + +=item * + +The C configuration macro has been removed. It was almost +undocumented and it has been disabled by default since Perl 5.10.0. Its purpose +was to force all GVs to initialize their SV slot on creation. [L] + +=back + +=head1 Testing + +Tests were added and changed to reflect the other additions and +changes in this release. Furthermore, these changes were +made: + +=over 4 + +=item * + +Karl Williamson gave a talk at TPRC 2025 asking people to contribute +tests to find old issues that are no longer a problem, and todo tests +to reflect reproduction cases for known outstanding bugs. +(L