Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions embed.fnc
Original file line number Diff line number Diff line change
Expand Up @@ -5362,8 +5362,8 @@ i |I32 |sv_i_ncmp |NN SV * const a \
|NN SV * const b
i |I32 |sv_i_ncmp_desc |NN SV * const a \
|NN SV * const b
i |I32 |sv_ncmp |NN SV * const a \
|NN SV * const b
i |I32 |sv_ncmp |NN SV *a \
|NN SV *b
i |I32 |sv_ncmp_desc |NN SV * const a \
|NN SV * const b
# if defined(USE_LOCALE_COLLATE)
Expand Down
8 changes: 7 additions & 1 deletion pod/perldelta.pod
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,13 @@ manager will later use a regex to expand these into links.

=item *

XXX
sort() optimizes well known comparisons from calling the OP tree for a
comparison block into a call to a C function. The C function used for
overloaded numeric comparisons did not handle the case where there was
no comparison overload but there was a numeric ("0+") overload
correct, losing precision for large overloaded integer arguments that
are not exactly representable as a Perl floating point value (NV).
[GH #23956]

=back

Expand Down
20 changes: 16 additions & 4 deletions pp_sort.c
Original file line number Diff line number Diff line change
Expand Up @@ -1310,12 +1310,23 @@ S_sortcv_xsub(pTHX_ SV *const a, SV *const b)


PERL_STATIC_FORCE_INLINE I32
S_sv_ncmp(pTHX_ SV *const a, SV *const b)
S_sv_ncmp(pTHX_ SV *a, SV *b)
{
I32 cmp = do_ncmp(a, b);

PERL_ARGS_ASSERT_SV_NCMP;

/* Numify since do_ncmp will just SvNV() non-IVs.

Even for the non-overloading case, if RVs are allocated with
large 64-bit addresses (only theoretically possible I think)
the bottom bits of the RV might be lost.
*/
if (SvROK(a))
a = sv_2num(a);
if (SvROK(b))
b = sv_2num(b);

I32 cmp = do_ncmp(a, b);

if (cmp == 2) {
if (ckWARN(WARN_UNINITIALIZED)) report_uninit(NULL);
return 0;
Expand Down Expand Up @@ -1359,7 +1370,7 @@ S_sv_i_ncmp_desc(pTHX_ SV *const a, SV *const b)
#define SORT_NORMAL_RETURN_VALUE(val) (((val) > 0) ? 1 : ((val) ? -1 : 0))

PERL_STATIC_FORCE_INLINE I32
S_amagic_ncmp(pTHX_ SV *const a, SV *const b)
S_amagic_ncmp(pTHX_ SV *a, SV *b)
{
SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp_amg);

Expand All @@ -1375,6 +1386,7 @@ S_amagic_ncmp(pTHX_ SV *const a, SV *const b)
return SORT_NORMAL_RETURN_VALUE(d);
}
}

return S_sv_ncmp(aTHX_ a, b);
}

Expand Down
2 changes: 1 addition & 1 deletion proto.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion t/op/sort.t
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ BEGIN {
set_up_inc('../lib');
}
use warnings;
plan(tests => 205);
plan(tests => 206);
use Tie::Array; # we need to test sorting tied arrays

# these shouldn't hang
Expand Down Expand Up @@ -964,6 +964,21 @@ is("@b", "1 2 3 3 4 5 7", "comparison result as string");
is($cs, 2, 'overload string called twice');
}

{
# GH 23956 - amagic_ncmp didn't handle numeric conversions
# properly
package GH23956 {
use overload
fallback => 1,
"0+" => sub { $_[0][0] };
}
my @data = map {
bless [ $_ ], "GH23956"
} ~0, ~0-1;
my @sorted = sort { $a <=> $b } @data;
is $sorted[0]+0, $data[1], "sort of 0+ overloaded values";
}

fresh_perl_is('sub w ($$) {my ($l, $r) = @_; my $v = \@_; undef @_; $l <=> $r}; print join q{ }, sort w 3, 1, 2, 0',
'0 1 2 3',
{stderr => 1, switches => ['-w']},
Expand Down
Loading