Search code examples
cstringraspberry-piraspberry-pi3string.h

strtol resulting in a segmentation fault on the raspberry pi 3 b+


I have this problem that strtol doesn't work and results in my C program crashing. I am using a Raspberry Pi 3 b+ but that probably doesn't matter.

My program (which is a command line tool to control shift registers) uses strtol for parsing through the command line arguments the program gets.

Here's the output I get: fish: Job 2, “./a.out -p 16 -w 0xff” terminated by signal SIGSEGV (Addroundary error)

And here's the output on gdp:

Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (
    nptr=0x76f72968 <_nl_C_LC_CTYPE_toupper+512> "", 
    nptr@entry=0x7efff6e9 "16", endptr=0x7efff6e9, 
    base=<optimized out>, group=group@entry=0, 
    loc=0x76fa1c70 <_nl_global_locale>) at strtol_l.c:484
484     strtol_l.c: No such file or directory.

The following is the code:

else if(!strcmp(argv[arg], "-p") || !strcmp(argv[arg], "-pins")) {
     if(argc <= arg+1)
         return 1;

     pins = strtol(argv[++arg], endptr, 0);
}

The command line argument parsing happens like so:

uint8_t arg, pins;
char **endptr;
uint64_t writeValue;
bool valueGiven; // The other bools that I define are irrelevant

for(arg = 1; arg < argc; arg++) {
    if(!strcmp(argv[arg], "-w") || !strcmp(argv[arg], "-write")) {
        if(argc <= arg+1)
            return 1;

        writeValue = strtol(argv[++arg], endptr, 0); // error happens here too

        valueGiven = true;
    }

    else if(!strcmp(argv[arg], "-p") || !strcmp(argv[arg], "-pins")) {
        if(argc <= arg+1)
            return 1;

        pins = strtol(argv[++arg], endptr, 0);
    }

    // There are more arguments but those are irrelevant
}

And I run the program like this: ./a.out -p 16 -w 0xFF

This error is very odd for the exact same thing worked before, could this be a case of data corruption?


Solution

  • Your char **endptr is uninitialized. It needs to point to a char * where the address of the first unconverted character will be stored. Instead, yours points nowhere, so strtol is going to try to write to whatever bogus memory location it points to, and very likely crash.

    GCC and clang should both issue warnings about the uninitialized variable if you enable -Wall. Example. Always use compiler warnings, and don't ignore them!

    Normally you would declare a char * variable and pass its address:

    char *end;
    strtol(argv[++arg], &end, 0);