Skip Menu |

This queue is for tickets about the Search-Binary CPAN distribution.

Report information
The Basics
Id: 52326
Status: rejected
Priority: 0/
Queue: Search-Binary

People
Owner: xaerxess [...] gmail.com
Requestors: friedm [...] mcb.harvard.edu
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.95
Fixed in: (no value)



Subject: possible bug in Search::Binary
Date: Tue, 01 Dec 2009 12:15:11 -0500
To: bug-Search-Binary [...] rt.cpan.org
From: Brad Friedman <friedm [...] mcb.harvard.edu>
Although the documentation says that search is guaranteed to be restricted to the range $min to $max inclusive, it is actually possible to go one-past-the-end, if the search key compares larger than the entire search set. This could potentially lead to undesirable auto-vivification. Maybe users should be made aware to write the reader function in a way that protects against this, or perhaps Search::Binary should be changed to prevent reading at position $max + 1. Note that this is not a problem when searching an array of scalars, since although $x[$pos]{key} will autovivify $x[$pos] to refer to an empty hash, $x[$pos] alone will not autovivify $x[$pos]. Example: #!/usr/bin/perl use strict; use Search::Binary; my @x = ({a => 1}, {a => 4}, {a => 5}, {a => 9}, {a => 12}); my $last_pos; sub reader { my (undef, $val, $pos) = @_; $pos = $last_pos + 1 unless defined $pos; $last_pos = $pos; return ($val <=> $x[$pos]{a}, $pos); } foreach my $x (15, 15) { my $next_pos = binary_search(0, $#x, $x, \&reader, undef); print "Next_pos of $x is $next_pos\n"; } Output is Next_pos of 15 is 5 Next_pos of 15 is 6 But ought to be Next_pos of 15 is 5 Next_pos of 15 is 5 Users can fix it by protecting non-existent array elements... sub reader { my (undef, $val, $pos) = @_; $pos = $last_pos + 1 unless defined $pos; $last_pos = $pos; #### Next two lines different #### my $a = exists $x[$pos] ? $x[$pos]{a} : undef; return ($val <=> $a, $pos); } Or Search::Binary could be changed.
On Wt 01 Gru 2009, 11:53:26, friedm@mcb.harvard.edu wrote: Show quoted text
> > Although the documentation says that search is guaranteed to be > restricted to the range $min to $max inclusive, it is actually possible > to go one-past-the-end, if the search key compares larger than the > entire search set. This could potentially lead to undesirable > auto-vivification. Maybe users should be made aware to write the reader > function in a way that protects against this, or perhaps Search::Binary > should be changed to prevent reading at position $max + 1. > > Note that this is not a problem when searching an array of scalars, > since although $x[$pos]{key} will autovivify $x[$pos] to refer to an > empty hash, $x[$pos] alone will not autovivify $x[$pos]. > > Example: > > #!/usr/bin/perl > use strict; > use Search::Binary; > > my @x = ({a => 1}, {a => 4}, {a => 5}, {a => 9}, {a => 12}); > my $last_pos; > sub reader { > my (undef, $val, $pos) = @_; > $pos = $last_pos + 1 unless defined $pos; > $last_pos = $pos; > return ($val <=> $x[$pos]{a}, $pos); > } > > > foreach my $x (15, 15) { > my $next_pos = binary_search(0, $#x, $x, \&reader, undef); > print "Next_pos of $x is $next_pos\n"; > } > > > > Output is > Next_pos of 15 is 5 > Next_pos of 15 is 6 > > But ought to be > Next_pos of 15 is 5 > Next_pos of 15 is 5 > > > Users can fix it by protecting non-existent array elements... > sub reader { > my (undef, $val, $pos) = @_; > $pos = $last_pos + 1 unless defined $pos; > $last_pos = $pos; > #### Next two lines different #### > my $a = exists $x[$pos] ? $x[$pos]{a} : undef; > return ($val <=> $a, $pos); > } > > > Or Search::Binary could be changed. >
Because subs which are used as readers are generally statefull (due to design decisions of Search::Binary) your example isn't valid - you should reset your reader somehow. See this code, which seems OK: use strict; use Test::More; END { done_testing } use Search::Binary; sub make_reader { my ( $array ) = @_; my $last_pos; return sub { my (undef, $val, $pos) = @_; $pos = $last_pos + 1 unless defined $pos; $last_pos = $pos; return ($val <=> $array->[$pos]{a}, $pos); } } my @x = ({a => 1}, {a => 4}, {a => 5}, {a => 9}, {a => 12}); foreach my $x (15, 15) { my $next_pos = binary_search(0, $#x, $x, make_reader([ @x ]), undef); is $next_pos, 5; }