From 5cf6f7057d37c134d9987cddb41ec56ca64551b9 Mon Sep 17 00:00:00 2001 From: Diab Jerius Date: Mon, 24 Jul 2023 13:11:15 -0400 Subject: [PATCH] vsearch: fix segv if vsearch $x arg is empty; add support for bad values in $vals argument --- Basic/Primitive/primitive.pd | 47 +++++++++++++++++++++++++++--------- t/primitive/vsearch.t | 27 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/Basic/Primitive/primitive.pd b/Basic/Primitive/primitive.pd index 0c027e932..998a9528d 100644 --- a/Basic/Primitive/primitive.pd +++ b/Basic/Primitive/primitive.pd @@ -2913,17 +2913,39 @@ for my $func ( [ my $code = undent q[ - PDL_Indx n1 = $SIZE(n)-1; - PDL_Indx low = %LOW%; - PDL_Indx high = %HIGH%; - PDL_Indx mid; + if ( $SIZE(n) == 0 ){ + broadcastloop %{ + loop(n) %{ + $SETBAD(idx()); + %} + %} + } + else { + broadcastloop %{ - $GENERIC() value = $vals(); + loop(n) %{ - /* determine sort order of data */ - int up = %UP%; - %CODE% - ---- + if ( $ISGOOD(vals()) ) { + PDL_Indx n1 = $SIZE(n)-1; + PDL_Indx low = %LOW%; + PDL_Indx high = %HIGH%; + PDL_Indx mid; + + $GENERIC() value = $vals(); + + /* determine sort order of data */ + int up = %UP%; + %CODE% + } + + else { + $SETBAD(idx()); + } + %} + + %} + } + ---- ]; my $doc = undent q[ @@ -2936,7 +2958,8 @@ for my $func ( [ $idx = %FUNC%($vals, $x); C<$x> must be sorted, but may be in decreasing or increasing - order. + order. if C<$x> is empty, then all values in C<$idx> will be + set to the bad value. %PRE% %BODY% @@ -2952,8 +2975,8 @@ for my $func ( [ pp_def( $func, - HandleBad => 0, - BadDoc => 'needs major (?) work to handles bad values', + HandleBad => 1, + BadDoc => 'bad values in vals() result in bad values in idx()', Pars => 'vals(); x(n); indx [o]idx()', GenericTypes => $F, # too restrictive ? Code => $code, diff --git a/t/primitive/vsearch.t b/t/primitive/vsearch.t index 30437f2c5..2fdedd321 100644 --- a/t/primitive/vsearch.t +++ b/t/primitive/vsearch.t @@ -3,6 +3,7 @@ use strict; use warnings; use Test2::V0 '!float'; +use Test2::Util; use PDL::LiteF; use Test::Lib; @@ -375,6 +376,14 @@ for my $mode ( sort keys %search ) { $so->{equal} ), 'equal elements'; + my $badmask = $so->{x}->random < 0.25; + my $badx = $so->{x}->setbadif( $badmask ); + my $bad_eq = $so->{equal}->setbadif( $badmask ); + + ok tapprox( vsearch( $badx, $so->{x}, { mode => $mode } ), + $bad_eq ), + 'equal elements w/ bad vals'; + ok tapprox( vsearch( $so->{x} - 5, $so->{x}, { mode => $mode } ), $so->{nequal_m} ), @@ -446,4 +455,22 @@ for my $mode ( sort keys %search ) { ok tapprox( $indx0, $indx1 ), 'explicit ndarray == implicit ndarray'; } +subtest regressions => sub { + + subtest '$xs->is_empty' => sub { + + skip 'check for regression requires fork' unless Test2::Util::CAN_FORK; + require Test2::AsyncSubtest; + + my $ast = Test2::AsyncSubtest->new( name => 'vsearch' ); + $ast->run_fork( + sub { + ok lives { pdl( [0] )->vsearch_bin_inclusive( pdl( [] ) ) } + } + ); + $ast->finish; + + }; + +}; done_testing;