Perl provides two sets of comparison operators: one set for working with numbers and one set for working with strings.
Numbers | Strings |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Do not use the number comparison operators on nonnumeric strings. Likewise, do not use the string comparison operators on numbers.
Noncompliant Code Example (Numbers)
This noncompliant code example improperly uses eq
to test two numbers for equality.
my $num = 2; print "Enter a number\n"; my $user_num = <STDIN>; chomp $user_num; if ($num eq $user_num) {print "true\n"} else {print "false\n"};
This code will print true
if the user enters 2
, but false
if the user enters 02
,
Compliant Solution (Numbers)
This compliant solution uses ==
, which interprets its arguments as numbers. This code therefore prints true
even if the right argument to ==
is initialized to some different string like 02
.
my $num = 2; print "Enter a number\n"; my $user_num = <STDIN>; chomp $user_num; if ($num == $user_num) {print "true\n"} else {print "false\n"};
Noncompliant Code Example (Strings)
This noncompliant code example improperly uses ==
to test two strings for equality.
sub check_password { my $correct = shift; my $password = shift; # encrypt password if ($password == $correct) { return true; } else { return false; } }
The ==
operator first converts its arguments into numbers by extracting digits from the front of each argument (along with a preceding +
or -
). Nonnumeric data in an argument is ignored, and the number consists of whatever digits were extracted. A string such as "goodpass"
has no leading digits, so it is converted to the numeral 0. Consequently, unless either $password
or $correct
contains leading digits, they will both be converted to 0 and will be considered equivalent.
Compliant Solution (Strings)
This compliant solution uses eq
, which interprets its arguments as strings.
sub check_password { my $correct = shift; my $password = shift; # encrypt password if ($password eq $correct) { return true; } else { return false; } }
Risk Assessment
Confusing the string comparison operators with numeric comparison operators can lead to incorrect program behavior or incorrect program data.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP35-PL | Low | Likely | Low | P9 | L2 |
Automated Detection
Tool | Diagnostic |
---|---|
Perl::Critic | ValuesAndExpressions::ProhibitMismatchedOperators |
Bibliography
5 Comments
David Svoboda
I've a preference for "non-numeric" rather than "nonnumeric". I can't find the term in the Perl docs, so I'm not sure what the Perl community prefers. Google however provides:
So I guess we can use "nonnumeric".
Edward Avis
The first example with "02" looks distinctly odd and contravenes INT00-PL. I think it would be better to give an example something like:
my $expected = 7;
my $got = <STDIN>;
chomp $got;
if ($got eq $expected)... # noncompliant, accepts '7' but not '07' or '7.0'
if ($got == $expected) ... # ok
David Svoboda
Agreed, I changed the example.
Anonymous
"Compliant Solution (Numbers)" is identical to "Noncompliant Code Example (Numbers)"... in the compliant solution "eq" should be "==" as the text describes.
David Svoboda
Whoops, fixed, thanks!