This service will be undergoing maintenance at 00:00 UTC, 2017-10-23 It is expected to last about 30 minutes
Bug 60534 - perl sort function broken
perl sort function broken
Status: CLOSED RAWHIDE
Product: Red Hat Linux
Classification: Retired
Component: perl (Show other bugs)
7.2
All Linux
medium Severity high
: ---
: ---
Assigned To: Chip Turner
David Lawrence
http://www.gurulabs.com/files/perl-te...
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2002-03-01 02:57 EST by Dax Kelson
Modified: 2010-08-26 15:58 EDT (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2002-03-01 03:25:35 EST
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Dax Kelson 2002-03-01 02:57:33 EST
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2.1) Gecko/20010901

Description of problem:
When using a subroutine with sort, the $a and $b are set incorrectly. I wrote a
small test case, it is broken in perl-5.6.0-17 (what ships with RH7.2), it works
fine with 5.6.1 and 5.004_05.

Here are the $a and $b sent to the subroutine:

comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10

It should be this (Perl 5.6.1 on a NetBSD box):

comparing kim-1st August 1975 22:20 WITH dax-4th April 1975 14:10
comparing bryan-8th January 1972 17:30 WITH dax-4th April 1975 14:10
comparing rick-28th May 1978 17:30 WITH bryan-8th January 1972 17:30
comparing rick-28th May 1978 17:30 WITH dax-4th April 1975 14:10
comparing rick-28th May 1978 17:30 WITH kim-1st August 1975 22:20
comparing sarah-8th January 1972 12:30 WITH bryan-8th January 1972 17:30
comparing heather-28th May 1978 17:30 WITH sarah-8th January 1972 12:30
comparing heather-28th May 1978 17:30 WITH bryan-8th January 1972 17:30
comparing heather-28th May 1978 17:30 WITH dax-4th April 1975 14:10
comparing heather-28th May 1978 17:30 WITH kim-1st August 1975 22:20
comparing heather-28th May 1978 17:30 WITH rick-28th May 1978 17:30

Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
1.Try test case
2.broken with perl that comes with RHL 7.2
3.Works with perl 5.6.1 and 5.004_05	

Actual Results:  broken on RH7.2 works on 5.6.1 on other platforms

Expected Results:  same output as 5.6.1 on other platforms

Additional info:

sort is pretty fundamental. I consider this a major problem. I stopped by #perl
and got agreement from the "perl gods".

I wasted 8 hours of work today thinking there was a problem with my code.

Here is the test case:

#########################
#!/usr/bin/perl

use Date::Manip;

@list = ('dax-4th April 1975 14:10', 'kim-1st August 1975 22:20', 'bryan-8th
January 1972 17:30', 'rick-28th May 1978 17:30', 'sarah-8th January 1972 12:30',
'heather-28th May 1978 17:30');

@sorted = sort by_birthdate @list;

sub by_birthdate {
        my($retval,$datea,$dateb,$str1,$str2,$flag);
        (undef,$str1) = split(/-/,$a);
        (undef,$str2) = split(/-/,$b);
        print "comparing $a WITH $b\n"; # this is the first hint of prob
        if ($str1 eq $str2) {
                return(0);
        }
        $datea=&ParseDate($str1);
        $dateb=&ParseDate($str2);
        $flag=&Date_Cmp($datea,$dateb);
        if ($flag<0) {
                return(1);
        } else {
                return(-1);
        }
}


##########################
Comment 1 Dax Kelson 2002-03-01 03:25:30 EST
I checked and it is broken on the perl shipped with RHL 7.1 too.
Comment 2 Chip Turner 2002-03-01 07:30:14 EST
You're seeing the result of a bugfix in perl 5.6.1.  In earlier versions, the
sort() function was not fully reentrant.  This meant if your comparison function
used sort, it could confuse perl, resulting in bad sorting, core dumps, or other
various behavior.  Unfortunately, Date::Manip's ParseDate ends up using sort for
some kinds of input, thus triggering the bug you see.

The two options are upgrade to Perl 5.6.1 (not yet available for Red Hat 7.2,
though available in an unsupported version if you would like to test it) or to
work around the problem.  Below is a modified version of your script that works
in 5.6.0 and 5.6.1.  The key here is to do the ParseDate outside of your sorting
function, thus avoiding the problem.  The technique is called a Schwartzian
Transform, and is a bit convoluted, but the idea is to basically pre-compute
ParseDate for each element of the list to be sorted, then sort THAT list.

#!/usr/bin/perl

use Date::Manip;

@list = ('dax-4th April 1975 14:10', 'kim-1st August 1975 22:20',
         'bryan-8th January 1972 17:30', 'rick-28th May 1978 17:30',
         'sarah-8th January 1972 12:30', 'heather-28th May 1978 17:30');

@sorted = map { $_->[0] }
            sort by_birthdate
              map { [ $_, ParseDate((split(/-/, $_, 2))[1]) ] }
                @list;
print "Sorted:\n";
print "\t$_\n" foreach @sorted;

sub by_birthdate {
        my($retval,$datea,$dateb,$str1,$str2,$flag);
        # this is the first hint of prob
        print "comparing $a->[0] WITH $b->[0]\n";
        $flag=&Date_Cmp($a->[1],$b->[1]);
        if ($flag<0) {
                return(1);
        } elsif ($flag > 0) {
                return(-1);
        }
        else {
                return 0;
        }
}

Note You need to log in before you can comment on or make changes to this bug.