1

I am working on a school project and recently encountered a roadblock. I have tried to make date / time a pointer and to even use a dynamically allocated array but when I run this function I get a segmentation fault. When I change the code [Commented] to this, I get a Stack Smashing error instead.

Time createTime(char time[12]) {

    Time tm;
    
    // time[strcspn(time, "\r\n")] = '\0';
    // char** tokens = splitString(time, 3, ":");

    // tm.hour = atoi(tokens[0]);
    // tm.min = atoi(tokens[1]);
    // tm.sec = atoi(tokens[2]);

    tm.hour = 1;
    tm.min = 1;
    tm.sec = 1;

    // free(tokens);

    return tm;
}

Full code

#include "earthquakeData.h"

Date createDate(char date[12]) {

    Date dt;

    date[strcspn(date, "\r\n")] = '\0';
    char** tokens = splitString(date, 3, "/");

    dt.month = atoi(tokens[0]);
    dt.day = atoi(tokens[1]);
    dt.year = atoi(tokens[2]);

    free(tokens);

    return dt;
}

Time createTime(char time[12]) {

    Time tm;
    
    // time[strcspn(time, "\r\n")] = '\0';
    // char** tokens = splitString(time, 3, ":");

    // tm.hour = atoi(tokens[0]);
    // tm.min = atoi(tokens[1]);
    // tm.sec = atoi(tokens[2]);

    tm.hour = 1;
    tm.min = 1;
    tm.sec = 1;

    // free(tokens);

    return tm;
}

Earthquake earthquakeCreate(
        int id,
        char date[12], // Parametized as char in order to convert.
        char time[12], // Parametized as char in order to convert.
        float latitude, 
        float longitude,
        char type[20],
        float depth,
        float magnitude,
        char magnitudeType[3]
    ) {

        Earthquake qk;
        
        qk.id = id;
        strcpy(qk.countryCode, "OO"); // Placeholder até se efetuarem os cálculos.
        Date qkDate = createDate(date);
        Time qkTime = createTime(time);
        qk.latitude = latitude;
        qk.longitude = longitude;
        strcpy(qk.type, type);
        qk.depth = depth;
        qk.magnitude = magnitude;
        strcpy(qk.magnitudeType, magnitudeType);

        return qk;
}

PtList LOADEA(int* numImported) {

    // Atributos do ficheiro e declaração do comprimento da linha de texto.
    FILE* file;
    char* filename = "datasets/earthquakes.csv";
    char line[1024];

    // Abertura do ficheiro.
    file = fopen(filename, "r"); 
    if (file == NULL) {
        // Se não existir.
        printf("File not found\n");
        return NULL;
    }
    
    // Aloca-se a memória da lista de earthquakes.
    PtList list = listCreate(); 
    if(list == NULL) {
        printf("Insuficient memory for allocation\n");
        return NULL;
    }

    int t = 0;
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\r\n")] = '\0';

        if (strlen(line) > 0) {
            char** tokens = splitString(line, 9, ";");
            if (tokens != NULL) {

                listAdd(list, t, earthquakeCreate(
                    atoi(tokens[0]),
                    tokens[1],
                    tokens[2],
                    atof(tokens[3]),
                    atof(tokens[4]),
                    tokens[5],
                    atof(tokens[6]),
                    atof(tokens[7]),
                    tokens[8]
                ));

                t++;
                // Liberta-se a memória associada aos tokens.
                free(tokens);
            }
        } 
    }

    // Fecha-se o ficheiro.
    fclose(file);

    *numImported = t - 1;

    return list;
}

The struct

/**
 * @brief Date struct.
 * 
 */
typedef struct date {
    int day, month, year;
} Date;

/**
 * @brief Time struct.
 * 
 */ 
typedef struct time {
    int hour, min, sec;
} Time;

/**
 * @brief Earthquake struct.
 * 
 */
typedef struct earthquake {
    int id;
    // Código de 2 letras do país ou território mais próximo (countryLocation)
    char countryCode[3]; // Calculado a partir das localizações durante importação
    Date date;
    Time time;
    float latitude;
    float longitude; 
    char type[20]; // Earthquake | Explosion | Nuclear Explosion | Rock Burst
    float depth;
    float magnitude;
    char magnitudeType[3]; // MB | MD | MH | ML | MS | MW
} Earthquake;

The splitString function

char** splitString(char *string, int nTokens, const char *delim) {
    char **tokens = (char**) malloc(sizeof(char*) * nTokens);
    int index = 0;
    int len = strlen(string);

    // Remove possible carriage return '\r' in file text lines and/or
    // Replace newline with terminator character
    len--;
    if (string[len-1]==13) 
        len--;
    string[len] = '\0'; 

    tokens[index++] = &string[0];
    for(int i=0; i < len; i++) {
        if( string[i] == delim[0] ) {
            string[i] = '\0';
            if( i < len - 1 ) {
                tokens[index++] = &string[i] + 1;
            }           
        }
    }
    return tokens;
}

Here is an example of the CSV file:

1;01/02/1965;13:44:18;19.246;145.616;Earthquake;131.6;6;MW

listCreate(), listAdd() and ensureCapacity()

typedef struct listImpl {
    ListElem* elements;
    int size; 
    int capacity;
} ListImpl;

bool ensureCapacity(PtList list) {
    if (list->size == list->capacity) {
        int newCapacity = list->capacity * 2;
        ListElem* newArray = (ListElem*) realloc( list->elements, 
                                newCapacity * sizeof(ListElem) );
        
        if(newArray == NULL) return false;

        list->elements = newArray;
        list->capacity = newCapacity;
    }
    
    return true;
}

PtList listCreate() {
    int initialCapacity = 10;
    PtList list = (PtList)malloc(sizeof(ListImpl));
    if (list == NULL) return NULL;

    list->elements = (ListElem*)calloc(initialCapacity,
                                        sizeof(ListElem));

    if (list->elements == NULL) {
        free(list);
        return NULL;    
    }

    list->size = 0;
    list->capacity = initialCapacity;

    return list;
}

int listAdd(PtList list, int rank, ListElem elem) {
    if (list == NULL) return LIST_NULL;
    if (rank < 0 || rank > list->size) return LIST_INVALID_RANK;
    if(!ensureCapacity(list)) return LIST_FULL;

    /* make room for new element at index 'rank' */
    for(int i = list->size; i > rank; i--) {
        list->elements[i] = list->elements[i-1];
    }

    list->elements[rank] = elem;

    list->size++;

    return LIST_OK;
}

And finally, the main function

int main() {

    PtMap countryStats;
    CountryLocation* countries;
    PtList earthquakes;

    /* Command interpreter. */
    char command[100];  
    while (true) {
        
        readString(command, 100);

        if (strcasecmp(command, "LOADCL") == 0) {
            countries = LOADCL(&numImported);
            sizeCL = numImported;
            if (countries != NULL) {
                printf("%d country location records imported\n", numImported);
            }
        }
        else if (strcasecmp(command, "LOADEA") == 0) {
            earthquakes = LOADEA(&numImported);
            if (earthquakes != NULL) {
                listPrint(earthquakes);
                printf("%d earthquake records imported\n", numImported);
            }
        }
        else if (strcasecmp(command, "LOADST") == 0) {
            countryStats = LOADST(&numImported);
            if (countryStats != NULL) {
                printf("%d country records imported\n", numImported);
            }
        }
        else {
            printf("Command not found.");
        }

        waitForKeypress();  
    }

    return EXIT_SUCCESS;
}

The function is called when the user inputs LOADEA to the console, it's worth noting that there are no problems in other similar functions, only when LOADEA is called, none of the other functions use list either. The teacher himself provided the listCreate() and listAdd() methods so the problem isn't there. Im pretty sure the solution is simple. I know a segmentation fault means that im trying to access memory that "doesn't exist" but I just don't understand where and why. I have tried to change the initialCapacity in listCreate() but to no avail.

hrodric
  • 390
  • 2
  • 12
  • Please copy-paste the full program in a big block, including all function bodies. Without that we can only guess. – pts Jun 15 '23 at 19:02
  • I've edited the question – hrodric Jun 15 '23 at 19:09
  • Compile it with `gcc -g -fsanitize=address`, and fix each issue it reports. – pts Jun 15 '23 at 19:20
  • Run it in a debugger, see in which line it crashes. – pts Jun 15 '23 at 19:20
  • What have you tried already? What does your teacher recommend? – pts Jun 15 '23 at 19:21
  • The question still doesn't contain the full program in a single, big code block. We can still only guess on what exactly you are compiling and running. Why don't you tell us? – pts Jun 15 '23 at 19:23
  • I just compiled it using those flags. ==13072==Hint: this fault was caused by a dereference of a high value address (see register values below). Dissassemble the provided pc to learn which register was used. #0 0x7f7bbce47580 in __GI_____strtol_l_internal ../stdlib/strtol_l.c:291 #1 0x7f7bbd2616be in __interceptor_atoi ../../../../src/libsanitizer/asan/asan_interceptors.cpp:518 #2 0x55ac6fd53a43 in createDate /home/r/Documents/en-assignment-bs_202200217/earthquakeData.c:11, can't place the rest here – hrodric Jun 15 '23 at 19:25
  • Im using Ubuntu and the rest of the program just takes in user input, I've tried allocating memory for date and time, making them pointers, using dynamic arrays, but when it reaches createDate it crashes with seg fault. – hrodric Jun 15 '23 at 19:27
  • What is on line 11 of earthquakeData.c? – EdmCoff Jun 15 '23 at 19:48
  • dt.day = atoi(tokens[1]); @EdmCoff – hrodric Jun 15 '23 at 19:49
  • Can you provide your splitString function? The reason for asking for a full program (a minimally reproducible example) isn't because the error is likely to be in other parts of the code. The reason is that someone could copy-'n-paste the full program and use their own debugger and likely know within 30 seconds what the error is instead of needing to ask you further questions or make guesses. – EdmCoff Jun 15 '23 at 19:54
  • I've edited the question again including the main function and splitString, both LOADCL and LOADST work but they aren't using list. – hrodric Jun 15 '23 at 20:02
  • You can copy-paste the long output (yes, indeed, absolutely, each line is relevant, please don't truncate it) back to your question. – pts Jun 15 '23 at 20:29
  • You still haven't included your full program in one, big code block to your question. (Several smaller code blocks are not helpful, because we cannot be sure in which order they appear, and what is there (by accident) between them. Also we cannot refer to line numbers.) You are wasting other people's time by not including (1) the entire program source code in one big code block; (2) the full error message. – pts Jun 15 '23 at 20:30

0 Answers0