incorrect strtol implementation

incorrect strtol implementation

I believe that the strtol implementation in the Intel ICC suite for Linux does not conform to the C standard. Program in question:

#include
#include


int main(void) {
char s[] = "--4";
char *endptr;

printf("%ld, ", strtol(s, &endptr, 10));
if ( !*endptr )
printf("Swallowed Everything ");
else
printf("-%c- ", *endptr);

return 0;
}

Output:
-2147483648, Swallowed Everything

Note that the return value is LONG_MIN on my platform, and endptr has been positioned to the null character in the string s.

I believe the correct behavior as per the C standard is to return 0, and position endptr at the start of the string (that is the first '-'. IOW, endptr == s). This is the behavior that is exhibited by gcc for the same code.

Platform:
Intel Pentium III, 1 GHz.

Compiler Details:
Intel C++ Compiler for 32-bit applications, Version 8.0 Build 20031016Z Package ID: l_cc_p_8.0.055
Copyright (C) 1985-2003 Intel Corporation. All rights reserved.
FOR NON-COMMERCIAL USE ONLY

Flags used:
-long_double
-O3
-ipo
-tpp6
-xK
-ansi
-Wall
-Wcheck

Operating System:
Linux 2.4.22-10mdkcustom i686 unknown unknown GNU/Linux

-nrk.

7 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

There is also an overflow and underflow issue. Here's a set of test case and their output (I have done this a bit hastily, so I urge you to try them out yourselves to verify behavior):


"--123" : Returns LONG_MIN and sets errno to ERANGE
"-+123" : Returns -123 and errno is not set
"+-123" : Returns LONG_MAX and sets errno to ERANGE
"++123" : Returns 123 and errno is not set.

LONG_MIN = -2147483648, LONG_MAX = 2147483647

"--2147483647" : Returns LONG_MIN and sets errno to ERANGE
"--2147483648" : Returns LONG_MIN and errno is not set!!
"--2147483649" : Returns LONG_MIN + 1 and errno is not set!!

"-+2147483647" : Returns -LONG_MAX and errno is not set!!
"-+2147483648" : Returns LONG_MIN and errno is not set!!
"-+2147483649" : Returns LONG_MIN and sets errno to ERANGE

"+-2147483647" : Returns LONG_MAX and sets errno to ERANGE
"+-2147483648" : Returns LONG_MAX and sets errno to ERANGE
"+-2147483649" : Returns LONG_MAX and errno is not set!!

"--2147483647" : Returns LONG_MIN and sets errno to ERANGE
"--2147483648" : Returns LONG_MIN and errno is not set!!
"--2147483649" : Returns LONG_MIN + 1 and errno is not set!!

-nrk.

Intel does not necessarily undertake to correct the functioning of glibc. I believe compatibility with gcc implementation on the same glibc is one of the goals. Perhaps you could run the same test with gcc, preferably a recent open version. If you find the gcc result more standard compliant, please file as an issue with premier.intel.com.

The gcc result is standard compliant and correct. The icc and icpc results are not. I wasn't aware that icc also used glibc by default. In this case, I am pretty sure it is using a different implementation of strtol (a strings on libcprts.a and libcprts.so.5 shows that the symbol strtol is somewhere in there), and not the glibc one. I will try to find out if the glibc version also exhibits the behavior when using icc.

-nrk.

Ok. Inspite of feeling that this was a red herring, I tried using glibc with icc. The glibc implementation is correct and produces standard-compliant results. It's the strtol implementation that's part of ICC that's incorrect. A few more cases where the output is not conforming:

strtol("0x", &endptr, 0);
endptr is incorrectly set to '0'. This should be treated as a decimal string and return 0, with endptr set to the 'X' in the input string.

strtol("0xG", &endptr, 0);
endptr is incorrectly set to the '0'. This should be treated as a decimal string and return 0, with endptr set to the 'X' in the input string.

strtol("0x", &endptr, 16);
strtol("0xG", &endptr, 16);
Same problems as the cases above.

From reading the description of strtol in ISO C9899: 7.20.1.4, and the BNF in 6.4.4.1, I am convinced that these cases are yielding non-conforming behavior. glibc confirms this by behaving as expected.

I don't have premier support (poor student hacking away thanklessly :-). So, if someone has premier support and feels this issue is important, feel free to use my input to file an issue with Intel premier support.

-nrk.

Message Edited by nrk on 02-16-2004 08:47 PM

If you download your own copy of the compiler from the Intel web page, you are invited to open an account. Someone has to go to the trouble, if it turns out to be such, of entering the data and uploading reproducing files. As you have done a good job of it so far, you may as well complete it.

Thanks for pointing that out tcprince. Since I usually give out a junk email ID and don't bother to go through the details of such registration emails, I missed the fact that even the non-commercial version can be used to raise issues with premier support. I've also been a bit sloppy (and incorrect) in describing the problem and testcases. I've now knocked together a decent test program, and uploaded it along with the issue I've raised with premier support. The issue number is 229058 for those interested. The test program that I used is at the end of this message (slightly modified because of tag restrictions in the forum).

-nrk.
#include
#include
#include


int main(void) {
char *s[] =
{ "--123",
"-+123",
"+-123",
"++123",
"--2147483646",
"--2147483647",
"--2147483648",
"--2147483649",
"-+2147483646",
"-+2147483647",
"-+2147483648",
"-+2147483649",
"+-2147483646",
"+-2147483647",
"+-2147483648",
"+-2147483649",
"++2147483646",
"++2147483647",
"++2147483648",
"++2147483649",
"0x",
"0xG",
"0X",
"0XG", };
char *endptr;
long l;
size_t i;

for ( i = 0; i != sizeof s/sizeof s[0]; ++i ) {
errno = 0;
l = strtol(s[i], &endptr, 0);
printf("%12ld, %d, $%c$ ",
l, errno == ERANGE ? 1 : 0, *endptr ? *endptr : '?' );
}

return 0;
}
/**
* Output with icc:
-2147483648, 1, $?$
-123, 0, $?$
2147483647, 1, $?$
123, 0, $?$
-2147483648, 1, $?$
-2147483648, 1, $?$
-2147483648, 0, $?$
-2147483647, 0, $?$
-2147483646, 0, $?$
-2147483647, 0, $?$
-2147483648, 0, $?$
-2147483648, 1, $?$
2147483647, 1, $?$
2147483647, 1, $?$
2147483647, 1, $?$
2147483647, 0, $?$
2147483646, 0, $?$
2147483647, 0, $?$
2147483647, 1, $?$
2147483647, 1, $?$
0, 0, $0$
0, 0, $0$
0, 0, $0$
0, 0, $0$

* Output with gcc:
0, 0, $-$
0, 0, $-$
0, 0, $+$
0, 0, $+$
0, 0, $-$
0, 0, $-$
0, 0, $-$
0, 0, $-$
0, 0, $-$
0, 0, $-$
0, 0, $-$
0, 0, $-$
0, 0, $+$
0, 0, $+$
0, 0, $+$
0, 0, $+$
0, 0, $+$
0, 0, $+$
0, 0, $+$
0, 0, $+$
0, 0, $x$
0, 0, $x$
0, 0, $X$
0, 0, $X$
*/

Message Edited by nrk on 02-16-2004 08:46 PM

Leave a Comment

Please sign in to add a comment. Not a member? Join today