0

This is a simplified code of my function:

myList* listFilesInDirectory(char* path) {
    DIR* dir = opendir(path);
    myList* list = createList();
    struct dirent* entry;

    while ((entry = readdir(dir)) != NULL) {
        myNode* node = createNode(entry->d_name);
        addToList(list, node);
    }
    closedir(dir);
    return list;
}

that I use in main function:

myList* sourceFiles = listFilesInDirectory("source/");
myList* destFiles = listFilesInDirectory("dest/");

The problem is that second invocation of function changes elements of list that was returned in first invocation. Elements of sourceFiles become changed after listFilesInDirectory("dest/"); is called.

But when I remove a closedir(dir) from function body, then everything works correctly and elements of sourceFiles are not changed.

I prepared a simple program https://pastebin.com/9pTYmpm2 so you can see what happens. Example result:

Result of test program

As you see, SourceFiles content 1 and SourceFiles content 2 are different. The first was printed before listFilesInDirectory("dest/") was invoked, and the second was printed after. But if I remove closedir(dir) from function all works correctly:

Result after removing closedir(dir)

What is going on here? Why does it happen? How to prevent it? Should I not use closedir() in my programs?

mrJoe
  • 500
  • 3
  • 13

1 Answers1

1

The problem seems to be that you are creating your node with the name straight from entry->d_name. But entry is stack allocated struct which will become invalid once your exit listFilesInDirectory.

An easy fix:

while ((entry = readdir(dir)) != NULL) {
        myNode* node = createNode(strdup(entry->d_name));
        addToList(list, node);
}

But I suggest you check the return values of everything: opendir, closedir, as well as strdup.

Uku Loskit
  • 40,868
  • 9
  • 92
  • 93
  • Why doesn't `struct` become invalid when I exit the function when `closedir(dir)` is removed? Does closing directory destroys all the structs that `readdir(dir)` returned? Does it mean that without `closedir()` all `struct dirent` returned by `readdir(dir)` are still in memory? Should I do `free(entry)` as the last thing in the loop? – mrJoe Mar 31 '18 at 15:28
  • Of course, I check return values of given functions. As I said in the post, this code is simplified as much as possible. – mrJoe Mar 31 '18 at 15:29
  • Many things can happen as you are accessing memory which you shouldn't. On my computer, I got garbled output instead of directory entries, for example. This can differ based on the compiler, OS etc. You must understand that the way you define the directory struct means that its lifetime is until the end of the function (stack allocated memory, a new function call creates a stack). What you want is heap allocated memory which remains valid until it is explicitly free'd. You can only free heap memory, stack frees itself. In principle you could also alloc the struct on the heap w/malloc. – Uku Loskit Mar 31 '18 at 15:36
  • Well, I still don't get what happens. Created list works as expected after is returned from `listFilesInDirectory`. When I invoke a function again my previous list become changed. But you say that structs exists until the end of a function so when list is returned it should be broken in that moment (because structs are destroyed) but is not. It is broken after creating another list. It doesn't makes sense for me. Especially, I don't see why `closedir()` impacts this code and why creating another list interferes with the first one. – mrJoe Mar 31 '18 at 16:04
  • 1
    In reality the memory isn't somehow zeroed out. It's "destroyed" in the sense of C programming conventions say that it isn't safe to use this memory addrsss for anything else anymore. It will be probably used for something else and that's when weird things start happening. – Uku Loskit Mar 31 '18 at 16:08
  • Thanks, now I understand why the list "works" after is returned from the first function invocation. But if I don't use `closedir()` it seems that even if I call `listFilesInDirectory` again and create another list, the first one is still working. If you comment out `closedir(dir)` you will see that output is the same in both tests. It is surprising. – mrJoe Mar 31 '18 at 16:18