http://qs321.pair.com?node_id=731064

I found a very odd bug today, triggered by a particular user's name. It started with an error message I've never seen before:

   Sort subroutine didn't return a numeric value at ...

The entry in perldiag suggests that I didn't use <=> or cmp or that I used them incorrectly. As it turned out, that was indeed true. The code in question was doing:

   foreach my $user (sort { $a->name <=> $b->name } @users) {

Since the names were alphanumeric obviously that should have been cmp not <=>. But I wondered, what was <=> returning if it wasn't returning a number? And since when did Perl even have values that couldn't be used numerically?

Printing out the data as it went through the sort revealed the culprit, one "Nan McEntire"! Apparently to Perl a string that starts with "Nan" is the same as NaN and <=> has special support for NaN values, returning undef! And sort has special un-support for something everything else in Perl does automatically, treating undefs as 0s.

Stunning! And, frankly, insane!

-sam

Replies are listed 'Best First'.
Re: Dangerous Names
by ikegami (Patriarch) on Dec 17, 2008 at 22:01 UTC

    "Nan McEntire" get numified to NaN on some systems, and the NaN check apparently causes <=> to return undef.

    $ perl -MDevel::Peek -e'Dump(0 <=> "Nan McEntire")' SV = NULL(0x0) at 0x503848 REFCNT = 2147483621 FLAGS = (PADBUSY,PADTMP,READONLY)
      Right, that's half the battle. Furthermore, sort barfs on undefs, which I find very odd. Pretty much everything else in Perl is happy to treat undef as 0, why not sort?

      -sam

        Pretty much everything else in Perl is happy to treat undef as 0, why not sort?
        I think you're confused
        D:\>perl -wle"print undef" Use of uninitialized value in print at -e line 1. D:\>perl -wle"warn undef" Use of uninitialized value in warn at -e line 1.
        Nothing in perl treats undef as 0 without barfing
        D:\>perl -we"print 1 <=> undef Use of uninitialized value in numeric comparison (<=>) at -e line 1. 1 D:\>perl -we"print 1 + undef Use of uninitialized value in addition (+) at -e line 1. 1 D:\>perl -we"print 1 - undef Use of uninitialized value in subtraction (-) at -e line 1. 1 D:\>
Re: Dangerous Names
by ccn (Vicar) on Dec 17, 2008 at 21:55 UTC
    Perl wants to see numbers around <=> (spaceship) operator and converts strings to numbers. "Nan" and "NaN" are both converted to zero.

    Update: Strings which start with "nan" (/^nan/i) are converted to nan, others which start with "inf" (/^inf/i) converted to inf. Others are converted to zero unless begin with digits.

    see perldoc peldata (Scalar values)

    #!/usr/bin/perl -l -- use strict; use warnings; my @s =qw(nan naNo inf InfInity infimum foo bar 123dd); print "$_ => ", $_+0 for @s; __END__ Argument "naNo" isn't numeric in addition (+) at a.pl line 7. Argument "infimum" isn't numeric in addition (+) at a.pl line 7. Argument "foo" isn't numeric in addition (+) at a.pl line 7. Argument "bar" isn't numeric in addition (+) at a.pl line 7. Argument "123dd" isn't numeric in addition (+) at a.pl line 7. nan => nan naNo => nan inf => inf InfInity => inf infimum => inf foo => 0 bar => 0 123dd => 123
      Incorrect! Proof:

      $ perl -e '@names = (["Nan Tregar"], ["Sam Tregar"]); @names = sort { +$a->[0] <=> $b->[0] } @names;' Sort subroutine didn't return a numeric value at -e line 1.

      Note that you have to work a little. Just a straight { $a <=> $b } gets optimized into something that doesn't do the NaN conversion.

      -sam

        I didn't need to do any extra work. See my post below.
        $ perl -v This is perl, v5.8.8 built for x86_64-linux-gnu-thread-multi
Re: Dangerous Names
by derby (Abbot) on Dec 18, 2008 at 15:23 UTC
      Haha! Probably his Mom. You gotta watch out for hacker Moms.

      -sam

      Nan is a nickname for Fernande, the French feminization of Ferdinand. I know this cause it's my grandmother's name. In other words, while Bobby Tables is xkcd, there are plenty of other real-life variations. For example, some system allow DEL as a shortcut for DELETE. I can imagine problems with "Del Monte". :-)

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

      :O

      I was thinking about posting the exact same thing as I started to read replies. I feel very unsatisfied right now.

      I'm so adjective, I verb nouns!

      chomp; # nom nom nom

Re: Dangerous Names
by Porculus (Hermit) on Dec 21, 2008 at 11:09 UTC
    Surely you should be happy about this? If Perl hadn't had this "insane" behaviour, you'd have been left with a silent bug that might have been very difficult to track down...
Re: Dangerous Names
by wol (Hermit) on Dec 23, 2008 at 17:29 UTC
    Hang on, I think I'm getting it...

    "Nan" is "not a number", and is treated as such.

    However, "not a number" is not a number, so is treated as zero.

    No - it's slipping away again...

    --
    use JAPH;
    print JAPH::asString();

      How about...

      "Nan" is a string representation of the floating point literal NaN. Like all string representations of floating point numbers it may be treated as it's numeric value.

      However, "not a number" is a non floating point string, so is treated as 0.

      Gaak! Trying to say this succinctly is a great way to twist your brain into knots.

      Disclaimer: IANALL, but I've played one in several companies.<grin/>

      G. Wade