How to overcome Segfault on accessing pointer to array

Segfault on accessing pointers

I’m developing simple GTK3 C app (using WSL2 and VSCode), but when I try to deserialize structs from file I’m getting Segfault (I’m not really familiar with gdb, so when I tried to debug I couldn’t really find the line which causes error).

My Code

Struct definition

typedef struct whatev {
    size_t id;
    char* name;
    int amount;
    float value;
    signed char state;
} SomeStruct;

Struct is defined in separate, included header, which doesen’t cause any problems during compilation (just for clarification)

Function causing segfault

SomeStruct* checkLine(char* str) {
    char* readString;
    int d1;
    float f1;
    
    sscanf(str, "%100[^;];%d;%f", readString, &d1, &f1);
    // printf("Checking line: Read name: \"%s\", amount=%d, value=%f\n", readString, d1, f1);
    if (readString[0] != '\0') {
        SomeStruct* newLine = malloc(sizeof(SomeStruct));
        // strcpy(newLine->name, readString);
        newLine->name = readString;
        newLine->amount = d1;
        newLine->value = f1;
        return newLine;
    }
    return NULL;
}
SomeStruct* createStructsFromFile(FILE* filestream, size_t fileLength) {
    printf("Create struct from file: start\n");
    SomeStruct* js = malloc(fileLength * sizeof(js));
    SomeStruct* currentItem = malloc(sizeof(js));
    size_t failed = 0;
    size_t j = 0;
    unsigned int buffer_size = 500;
    
    // ERROR: Segfault somewhere here

    for (size_t i = 0; i < fileLength; i++) {
        char buffer[buffer_size];
        fgets(buffer, buffer_size, filestream);
        if ((currentItem = checkLine(buffer)) != NULL) {
            currentItem->id = j;
            currentItem->state = 0;

            js[j] = *currentItem;
            currentItem = (SomeStruct*)malloc(sizeof(js));
            j++;
        }
        else
            failed++;  // TODO
    }
    printf("Create struct from file: Finished creating, failed reading %zd / %zd lines\n", failed, fileLength);
    return js;
}

My debugging attempt

Breakpoint 5 at 0x80031a6: file FileOperations/fileOperations.c, line 125.
(gdb) step
[LWP 22523 exited]
createStructsFromFile: before assignment currentItem[0] (KsiążkaZPolskimiZnakami) to js[0]
123                 js[j] = *currentItem;
(gdb) display js
13: js = (SomeStruct *) 0x85663e0
(gdb) display js[0]
14: js[0] = {id = 139820112, name = 0x0, amount = 137883733, value = 2.80259693e-44, state = 0 '\000'}
(gdb) display js[1]
15: js[1] = {id = 90194313216, name = 0xfffffff <error: Cannot access memory at address 0xfffffff>, 
  amount = 0, value = 0, state = 21 '\025'}
(gdb) display js[19]
16: js[19] = {id = 67174657, name = 0x0, amount = 0, value = -8.99305959e+35, state = 54 '6'}
(gdb) display currentItem
17: currentItem = (SomeStruct *) 0x83f34b0
(gdb) display currentItem->name
18: currentItem->name = 0x7ffffffecf30 "KsiążkaZPolskimiZnakami"
(gdb) step

Thread 1 "main" hit Breakpoint 5, createStructsFromFile (filestream=0x696b736c6f505a61, 
    fileLength=7763297035996459851) at FileOperations/fileOperations.c:125
125                 printf("createStructsFromFile: inserted %zdth struct\n\n", j);
13: js = (SomeStruct *) 0x85663e0
14: js[0] = {id = 0, name = 0x7ffffffecf30 "KsiążkaZPolskimiZnakami", amount = 12, 
  value = 3.99000001, state = 0 '\000'}
15: js[1] = {id = 90194313216, name = 0xfffffff <error: Cannot access memory at address 0xfffffff>, 
  amount = 0, value = 0, state = 21 '\025'}
16: js[19] = {id = 67174657, name = 0x0, amount = 0, value = -8.99305959e+35, state = 54 '6'}
17: currentItem = (SomeStruct *) 0x83f34b0
18: currentItem->name = 0x7ffffffecf30 "KsiążkaZPolskimiZnakami"
(gdb) step
createStructsFromFile: inserted 0th struct

126                 currentItem = malloc(sizeof(js));
13: js = (SomeStruct *) 0x85663e0
14: js[0] = {id = 0, name = 0x7ffffffecf30 "KsiążkaZPolskimiZnakami", amount = 12, 
  value = 3.99000001, state = 0 '\000'}
15: js[1] = {id = 90194313216, name = 0xfffffff <error: Cannot access memory at address 0xfffffff>, 
  amount = 0, value = 0, state = 21 '\025'}
16: js[19] = {id = 67174657, name = 0x0, amount = 0, value = -8.99305959e+35, state = 54 '6'}
17: currentItem = (SomeStruct *) 0x83f34b0
18: currentItem->name = 0x7ffffffecf30 "KsiążkaZPolskimiZnakami"
(gdb) step
start pętli 1

Thread 1 "main" received signal SIGSEGV, Segmentation fault.
0x00007ffffeae2657 in ?? ()

Sample database

KsiążkaZPolskimiZnakami;12;3.99
Book with a lot of spaces;44;2.99
OutOfStock;0;1.00
LiterallyFreeNotebook;99;0.00
NextLineTriesToMakeScanfError;1;255.12
;;
HopeThatReadingWillWork;12;66.72
ThisBookHas7Parts;3;12.50
لكن لا بد أن أوضح لك أن كل هذه الأفكار;6;12.5
ArabicAndNeat;8;11
NegativeQuantity;-12;5.00
NegativeValue;7;-2.22
!LL3G4L_$|gNS;10;7.5
 
AboveWasJustSpace;2;0.1
TooManyArguments;1;15.55;12
UnexpectedType;3232.1;55
71830;80085;AndOtherFunnyThings
\0;\0;\0
EscapeSequence\n\"exit(1);11;255.1
YesILoveDebugging,Why?;-0;-99999999999999.9999

Expectations

I want to use createStructsFromFile‘s output to populate GTK TreeView. I also tried using double pointers, but for debugging sake I simplified returns (size_t createStructsFromFile(FILE* filestream, size_t fileLength, JakasStruktura** js)

What’s wrong and how can I improve it?

If needed, code can be found on my GitHub

(commit)[https://github.com/ikarmus2001/ProjektC/commit/761a1f2000ee8ab1c32efd8449c1b95f8f11a2c1]

Thanks in advance

>Solution :

Code passes an uninitialized object readString to sscanf() leading to undefined behavior (UB). @Johnny Mopp

char* readString;
...
sscanf(str, "%100[^;];%d;%f", readString, &d1, &f1);  // bad

Instead

char readString[100+1];

Check return value

Test if scan was successful**

// sscanf(str, "%100[^;];%d;%f", readString, &d1, &f1);
if (sscanf(str, "%100[^;];%d;%f", readString, &d1, &f1) != 3) {
  Handle_bad_input();
}

Needs a copy of the string

Instead of coping a point, allocate data.

// newLine->name = readString;
newLine->name = malloc(strlen(readString) + 1);
if (newLine->name == NULL) {
  TBD_eror_handling();
}
strcpy(newLine->name, readString);

The earlier SomeStruct* newLine = malloc(sizeof(SomeStruct)); allocated memory for the struct, including the pointer: .name member. Yet the pointer still does not point to any allocated string.

Later code needs to free this allocation when done with the structure.

Leave a Reply