0

I had the following code, which prints the files in a folder that have an ending. It looks also by default files with the following ending "SCL_10m.tif". This is the version that worked so far:

#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "gdal/gdal.h"
#include "gdal/cpl_conv.h"
#include <stdio.h>
#include <time.h>


// Linked-List
typedef struct nlist{
    char *data;
    struct nlist *next;
}Node;

// Function to replace a string with another 
// string 
char* str_replace(char* string, const char* substr, const char* replacement) {
    char* tok = NULL;
    char* newstr = NULL;
    char* oldstr = NULL;
    int   oldstr_len = 0;
    int   substr_len = 0;
    int   replacement_len = 0;

    newstr = strdup(string);
    substr_len = strlen(substr);
    replacement_len = strlen(replacement);

    if (substr == NULL || replacement == NULL) {
        return newstr;
    }

    while ((tok = strstr(newstr, substr))) {
        oldstr = newstr;
        oldstr_len = strlen(oldstr);
        newstr = (char*)malloc(sizeof(char) * (oldstr_len - substr_len + replacement_len + 1));

        if (newstr == NULL) {
            free(oldstr);
            return NULL;
        }

        memcpy(newstr, oldstr, tok - oldstr);
        memcpy(newstr + (tok - oldstr), replacement, replacement_len);
        memcpy(newstr + (tok - oldstr) + replacement_len, tok + substr_len, oldstr_len - substr_len - (tok - oldstr));
        memset(newstr + oldstr_len - substr_len + replacement_len, 0, 1);

        free(oldstr);
    }

    free(string);

    return newstr;
}


Node* insert(Node*, char*);
void show(Node*);

//Function to insert an element in the linked-list
Node* insert(Node *Head, char *value)
{
    Node *new_string;
    new_string = (Node *)malloc(sizeof(Node));
    new_string->data = malloc(strlen(value)+1);
    strcpy(new_string->data,value);
    Node *check;
    check = (Node *)malloc(sizeof(Node));

    if(Head == NULL){
        Head = new_string;
        Head->next = NULL;
    }
    else{
        check = Head;
        while(check->next != NULL)
            check = check->next;

        check->next = new_string;
        new_string->next = NULL;
    }
    return Head;
}

//Function to show the elements in the linked-list
void show(Node *Head)
{
    Node *check;
    check = (Node *)malloc(sizeof(Node));
    check = Head;
    if (check == NULL){
        return;
    }

    while(check != NULL) {
        printf("%s", check->data);
        check=check->next;
    }
    printf("\n");
}

//Function to find the files in the folder recursively based on 
// a wildcard, and adding them to a linked-list
void listFilesRecursively(char *path, char *suffix);

//checks if a string ends with a substring
int string_ends_with(const char * str, const char * suffix)
{
    int str_len = strlen(str);
    int suffix_len = strlen(suffix);

    return 
        (str_len >= suffix_len) &&
        (0 == strcmp(str + (str_len-suffix_len), suffix));
}

void listFilesRecursively(char *basePath, char *suffix)
{
    char path[1000];
    struct dirent *dp;
    DIR *dir = opendir(basePath);
    Node *Head = NULL;

    if (!dir)
        return;

    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            if (string_ends_with(path, suffix))
                Head = insert(Head, path);
            listFilesRecursively(path, suffix);
        }
    }

    show(Head);
    closedir(dir);
}

int main()
{
    char path[100];
    char suffix[100];

    // Input path from user
    // Suffix Band Sentinel-2 of Type B02_10m.tif

    printf("Enter path to list files: ");
    scanf("%s", path);
    printf("Enter the wildcard: ");
    scanf("%s", suffix);
    char *SCL_suffix = "SCL_10m.tif";
    listFilesRecursively(path, suffix);
    listFilesRecursively(path, SCL_suffix);

    return 0;
}

I started working on this code, making some changes, the most important was that instead of printing the linked list generated in the function listFilesRecursively by calling show(Head), then I wanted to return the lists to the main function to make other processes (iterate over both lists simultaneously, that's future work).

However after doing that, and calling the function listFilesRecursively twice, in the main(), I run into a segmentation fault error.

According to some sources a segmentation fault occurs if a pass or return a pointer from a function that points something on the stack, a stack being a region of memory that stores temporary variables. I have been checking the listFIlesRecursively function, messing around with the pointers within, but I cannot get my head around the problem. A bit of help on the topic would be appreaciated.

Here is the modified version of my code that causes the segmentation fault.

include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "gdal/gdal.h"
#include "gdal/cpl_conv.h"
#include <stdio.h>
#include <time.h>


// Node Structure of Linked-List
typedef struct nlist{
    char *data;
    struct nlist *next;
}Node;

// Function to replace a string with another 
// string 
char* str_replace(char* string, const char* substr, const char* replacement) {
    char* tok = NULL;
    char* newstr = NULL;
    char* oldstr = NULL;
    int   oldstr_len = 0;
    int   substr_len = 0;
    int   replacement_len = 0;

    newstr = strdup(string);
    substr_len = strlen(substr);
    replacement_len = strlen(replacement);

    if (substr == NULL || replacement == NULL) {
        return newstr;
    }

    while ((tok = strstr(newstr, substr))) {
        oldstr = newstr;
        oldstr_len = strlen(oldstr);
        newstr = (char*)malloc(sizeof(char) * (oldstr_len - substr_len + replacement_len + 1));

        if (newstr == NULL) {
            free(oldstr);
            return NULL;
        }

        memcpy(newstr, oldstr, tok - oldstr);
        memcpy(newstr + (tok - oldstr), replacement, replacement_len);
        memcpy(newstr + (tok - oldstr) + replacement_len, tok + substr_len, oldstr_len - substr_len - (tok - oldstr));
        memset(newstr + oldstr_len - substr_len + replacement_len, 0, 1);

        free(oldstr);
    }

    free(string);

    return newstr;
}


Node* insert(Node*, char*);
void show(Node*);

// Function to insert an element to the Linked-List
Node* insert(Node *Head, char *value)
{
    Node *new_string;
    new_string = (Node *)malloc(sizeof(Node));
    new_string->data = malloc(strlen(value)+1);
    strcpy(new_string->data,value);
    Node *check;
    check = (Node *)malloc(sizeof(Node));

    if(Head == NULL){
        Head = new_string;
        Head->next = NULL;
    }
    else{
        check = Head;
        while(check->next != NULL)
            check = check->next;

        check->next = new_string;
        new_string->next = NULL;
    }
    return Head;
}

//Function to show the elements of the Linked-List
void show(Node *Head)
{
    Node *check;
    check = (Node *)malloc(sizeof(Node));
    check = Head;
    if (check == NULL){
        return;
    }

    while(check != NULL) {
        printf("%s", check->data);
        check=check->next;
    }
    printf("\n");
}

//Function to check if a string finishes with a suffix
int string_ends_with(const char * str, const char * suffix)
{
    int str_len = strlen(str);
    int suffix_len = strlen(suffix);

    return 
        (str_len >= suffix_len) &&
        (0 == strcmp(str + (str_len-suffix_len), suffix));
}


Node *listFilesRecursively(char*, char*);

//Function to find the files in a directory based on a wildcard
Node *listFilesRecursively(char *basePath, char *suffix)
{
    char path[1000];
    struct dirent *dp;
    DIR *dir = opendir(basePath);
    Node *Head = NULL;
    Node *Head_scl = NULL;

    //if (!dir)
    //    return;

    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            if (string_ends_with(path, suffix))
                Head = insert(Head, path);
            listFilesRecursively(path, suffix);
        }
    } 
    //show(Head);
    closedir(dir);
    return Head;
}


int main()
{
    char path[100];
    char suffix[100];

    // Input path from user
    // Suffix Band Sentinel-2 of Type B02_10m.tif

    printf("Enter path to list files: ");
    scanf("%s", path);
    printf("Enter the wildcard: ");
    scanf("%s", suffix);

    Node *B02_head;
    Node *SCL_head;
    B02_head = listFilesRecursively(path, suffix);
    char *suffix_scl = "SCL_10m.tif";
    SCL_head = listFilesRecursively(path, suffix_scl);
    show(B02_head);
    show(SCL_head);
    return 0;
}
Roger Almengor
  • 442
  • 5
  • 16
  • So you should debug your code and see at what instruction the segmentation fault occurs; A seg fault is an access violation: your application tries to access a memory address it is not allowed to. It is frequently due to dereferencing a pointer whose value if unvalid (like 0 or 0xFFFFFFFF). – Guillaume Petitjean Nov 12 '19 at 08:31
  • Thanks for the recommendation of using the debugger. I used gdb, and after running the ./list_dir_files file which is the file created after building the program, I received the following: ```Program received signal SIGSEGV, Segmentation fault. 0xb7e8eeeb in __readdir (dirp=0x0) at ../sysdeps/posix/readdir.c:44 44 ../sysdeps/posix/readdir.c: No such file or directory.``` – Roger Almengor Nov 12 '19 at 08:36
  • by pressing the backtrace I got the following: ```#0 0xb7e8eeeb in __readdir (dirp=0x0) at ../sysdeps/posix/readdir.c:44 #1 0x00400d2f in listFilesRecursively () #2 0x00400d1e in listFilesRecursively () #3 0x00400e05 in main ()``` How can man interpret the ouput of what the debugger tells? – Roger Almengor Nov 12 '19 at 08:38
  • 1
    Here we go again (and again and again and again). `check = (Node *)malloc(sizeof(Node));` and then immediately `check = Head;`. Can you explain this puzzling sequence to your nearest rubber duck? – n. m. could be an AI Nov 12 '19 at 08:39
  • 1
    You need to build with debugging enabled, the flag `-ggdb` does the trick. – n. m. could be an AI Nov 12 '19 at 08:40
  • ```check = (Node *)malloc(sizeof(Node)); and then immediately check = Head;``` With that line I tried to allocate space for the check variable of type Node to be created. Then I assign that to the Head of a linked list then it checks if the linked list is depleted when using the while(check != NULL), to print the string that every node in check has, and changes check to be the next. The question: could I get rid of check altogether and use the *Head argument within the void show() function? – Roger Almengor Nov 12 '19 at 08:41
  • 1
    If you are not familiar with gdb you can use an IDE that will allow to do step by step debug more "easily". – Guillaume Petitjean Nov 12 '19 at 08:41
  • 1
    *"and then immediately check = Head"* No, that's what `if (check == Head)` does. In the `else` branch, the line `check = Head;` leaks the memory allocated by `malloc`. – Bob__ Nov 12 '19 at 08:47
  • 1
    Could you try to compile with -g, and launch your program with valgrind then show the result ? :) PS : ```valgrind ./your_executable param param2 ...``` – Angevil Nov 12 '19 at 09:02
  • @Angevil I am on the way. I had to install Valgrind first :) – Roger Almengor Nov 12 '19 at 09:07
  • 1
    Great ! I've been using it to do memory debug for so long ;) – Angevil Nov 12 '19 at 09:09
  • The information looks more detailed. Thanks for the advice. – Roger Almengor Nov 12 '19 at 09:11
  • I ran the program and got the following: – Roger Almengor Nov 12 '19 at 09:12
  • ```==10364== Invalid read of size 4 ==10364== at 0x4917EEB: readdir (readdir.c:44) ==10364== by 0x108C92: listFilesRecursively (list_dir_files_4.c:130) ==10364== by 0x108C81: listFilesRecursively (list_dir_files_4.c:140) ==10364== by 0x108D68: main (list_dir_files_4.c:164) ==10364== Address 0x4 is not stack'd, malloc'd or (recently) free'd ==10364== ==10364==``` – Roger Almengor Nov 12 '19 at 09:12
  • ```==10364== Process terminating with default action of signal 11 (SIGSEGV) ==10364== Access not within mapped region at address 0x4 ==10364== at 0x4917EEB: readdir (readdir.c:44) ==10364== by 0x108C92: listFilesRecursively (list_dir_files_4.c:130) ==10364== by 0x108C81: listFilesRecursively (list_dir_files_4.c:140) ==10364== by 0x108D68: main (list_dir_files_4.c:164) ``` – Roger Almengor Nov 12 '19 at 09:13
  • 1
    ```==10364== HEAP SUMMARY: ==10364== in use at exit: 32,796 bytes in 1 blocks ==10364== total heap usage: 3 allocs, 2 frees, 34,844 bytes allocated ==10364== ==10364== LEAK SUMMARY: ==10364== definitely lost: 0 bytes in 0 blocks ==10364== indirectly lost: 0 bytes in 0 blocks ==10364== possibly lost: 0 bytes in 0 blocks ==10364== still reachable: 32,796 bytes in 1 blocks ==10364== suppressed: 0 bytes in 0 blocks ==10364== Rerun with --leak-check=full to see details of leaked memory ==10364== ``` – Roger Almengor Nov 12 '19 at 09:13
  • ```==10364== For counts of detected and suppressed errors, rerun with: -v ==10364== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) Segmentation fault (core dumped) ``` – Roger Almengor Nov 12 '19 at 09:14
  • 1
    So you meet 1 error "only", the input you send on list_dir_files_4.c, at line 130 seems to be wrong – Angevil Nov 12 '19 at 09:15
  • 1
    I am summarizing the advices given in my post, and reviewing my code line by line, I think I can figure out the problem with the memory leak, and fix it to have my code running. Thank you all. – Roger Almengor Nov 12 '19 at 09:24
  • I checked the entire code, and there is a problem with the while loop in the listFilesRecursively function. I found some information about it, and they say that when you use the dirent data structure you have to copy the actual string that makes the path to folder. I don't know what that mean. I found that post interesting. And the show function in my code did not cause the segmentation fault in this case. – Roger Almengor Nov 12 '19 at 21:03
  • https://stackoverflow.com/questions/53361551/segmentation-fault-core-dumped-using-stat-st-uid – Roger Almengor Nov 12 '19 at 21:03

0 Answers0