1

I am facing issue with c library function strtoull which is returning me wrong output.

   int main(int argc, char *argv[])
   {
    unsigned long long int intValue;

    if(atoi(argv[2]) == 1)
    {   
        intValue = strtoull((const char *)argv[1], 0, 10 );
    }
    else
    {
//  ...
    }

    printf("intValue of %s is %llu \n", argv[1], intValue);

    return 0;
    }   

I built them and generated 32 and 64 bit executables as str32_new and str64_new. But the output received from 32 bit exe is errorneous as wrong number is returned:

strtoull should had returned me number 5368709120 for the passed string "5368709120" but it returned me 1073741824.

# ./str32_new "5368709120" 1
intValue of 5368709120 is 1073741824 

I note that when I decrease one character from string then it shows proper output.

# ./str32_new "536870912" 1
intValue of 536870912 is 536870912 

glibc attached to 32 bit exe is

   # readelf -Wa /home/str32_new | grep strt
  [39] .shstrtab         STRTAB          00000000 002545 000190 00      0   0  1
  [41] .strtab           STRTAB          00000000 0032f8 0002a4 00      0   0  1
  0804a014  00000607 R_386_JUMP_SLOT        00000000   strtoull
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND strtoull@GLIBC_2.0 (2)
    55: 00000000     0 FILE    LOCAL  DEFAULT  ABS strtoull.c
    75: 00000000     0 FUNC    GLOBAL DEFAULT  UND strtoull@@GLIBC_2.0
    77: 08048534   915 FUNC    GLOBAL DEFAULT   15 my_strtoull

glibc attached to 64 bit exe is

 # readelf -Wa /home/str64_new | grep strt
  [39] .shstrtab         STRTAB          0000000000000000 001893 000192 00      0   0  1
  [41] .strtab           STRTAB          0000000000000000 002cd0 00029b 00      0   0  1
  0000000000601028  0000000700000007 R_X86_64_JUMP_SLOT     0000000000000000 strtoull + 0
     7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strtoull@GLIBC_2.2.5 (2)
    57: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS strtoull.c
    73: 00000000004006cc   804 FUNC    GLOBAL DEFAULT   15 my_strtoull
    82: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strtoull@@GLIBC_2.2.5

64 bit exe shows proper output but on some system it too behaves abnormally. Why is the strtoull in 32 bit exe behaving so and how to resolve this issue?

RKum
  • 758
  • 2
  • 12
  • 33

3 Answers3

2

Ok, so we've established that this is quite obviously happening due to an overflow, as the value matches what would happen if casted into 32bit int.

This however does not explain everything - you did use strtoull, not the shorter strtoul, and it indeed works on 64bit binary. If anything, I was surprised to see you were even able to call the longer version in your 32bit build (how did you build it by the way, with -m32? or on a special machine?)

This link, raises the possibility that there's some linkage phenomenon that makes strtoull get declared as int strtoll() (presumably the system can't support the original lib version), and so we get the value implicitly casted through int, before copied back to your unsigned long long.

Either way - this should have been warned against by the compiler, try setting it to c99 and raise the warning levels, maybe that would make it shout

Community
  • 1
  • 1
Leeor
  • 19,260
  • 5
  • 56
  • 87
  • Agreed. It might even be something as silly as not including headers for printf, and parameter being downcasted to int. – domen Oct 01 '13 at 15:46
  • 2
    I had not included stdlib.h. Including it resolves the issue. – RKum Oct 01 '13 at 19:41
1

I think that is due to overflow. int in 32bit can not hold a number that large (max is 4294967296). As Leeor said, 5368709120 & (0xffffffff) = 1073741824.

The type int is minimally 32 bits wide, and is only 32 bits wide on most (if not all) systems.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
CS Pei
  • 10,869
  • 1
  • 27
  • 46
0

You most likely forgot to #include <stdlib.h> and you probably did not enable any compiler warnings (like for using undeclared functions).

When a C compiler sees a function call to an undeclared function it blindly assumes int f(int) as prototype. In your case the return value of strtoull() will be int and so the value will be truncated to 32-bit.

(It is indeed quite strange that you get the correct result on a 64-bit system, where int is usually also just 32-bit.)

Johannes Overmann
  • 4,914
  • 22
  • 38