From 39e539e1e417d117889bd85432db013d0edc4069 Mon Sep 17 00:00:00 2001 From: Sergei Zhmylev Date: Mon, 27 Jan 2025 01:00:43 +0300 Subject: [PATCH] Fix uniqint SIGSEGV for objects with no int overload In case uniqint takes several objects, it always tries to call their int overload using amagic_call. This patch fixes the case when amagic_call returned NULL resulting into Segmentation Violation. Several tests are also added to ensure proper objects handling. Signed-off-by: Sergei Zhmylev --- ListUtil.xs | 6 ++++-- t/uniq.t | 28 +++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/ListUtil.xs b/ListUtil.xs index f67e9d4..ca7f7cf 100644 --- a/ListUtil.xs +++ b/ListUtil.xs @@ -1369,8 +1369,10 @@ CODE: /* coerce to integer */ #if PERL_VERSION >= 8 /* int_amg only appeared in perl 5.8.0 */ - if(SvAMAGIC(arg) && (arg = AMG_CALLun(arg, int))) - ; /* nothing to do */ + if(SvAMAGIC(arg)) { + if(!(arg = AMG_CALLun(arg, int))) + croak("No \"int\" method found in overloaded package"); + } else #endif if(!SvOK(arg) || SvNOK(arg) || SvPOK(arg)) diff --git a/t/uniq.t b/t/uniq.t index 7129552..330c8ca 100644 --- a/t/uniq.t +++ b/t/uniq.t @@ -3,7 +3,7 @@ use strict; use warnings; use Config; # to determine ivsize -use Test::More tests => 31; +use Test::More tests => 35; use List::Util qw( uniqstr uniqint uniq ); use Tie::Array; @@ -98,6 +98,32 @@ is_deeply( [ uniqint 6.1, 6.2, 6.3 ], 'uniqint on undef coerces to zero' ); } +{ + use Math::BigInt; + my ($obj1, $obj2, $obj3) = map { Math::BigInt->new($_) } 1, 1, 2; + + is_deeply( [ uniqint $obj1, $obj1 ], + [ $obj1 ], + 'uniqint removes repeated Math::BigInt objects' ); + + is_deeply( [ uniqint $obj1, $obj2 ], + [ $obj1 ], + 'uniqint removes subsequent Math::BigInt objects' ); + + is_deeply( [ uniqint $obj1, $obj2, $obj3 ], + [ $obj1, $obj3 ], + 'uniqint removes multiple subsequent Math::BigInt objects' ); +} + +{ + { package OverloadedPackageWithoutInt; use overload "+" => sub {} } + + my $obj1 = bless {}, "OverloadedPackageWithoutInt"; + + ok( !defined eval { uniqint $obj1 }, + 'package with no "int" overload throws exception' ); +} + SKIP: { skip('UVs are not reliable on this perl version', 2) unless "$]" >= 5.008000;