-1

EDIT : Note that It's not that I can't access the memory allocated by storeContents() in main() if you think so. Program crashes during the execution of storeContents()

The program fails here :

strcpy(contents[count], dir->d_name);
printf("Stored %s(out hiddenVisible)\n", dir->d_name); // for testing

It's strcpy() not the printf(), I added it just for the reference.

The debugger(gdb) says :

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f3cd72 in __strcpy_ssse3 () from /usr/lib/libc.so.6

I am making a program that involves the following function "storeContents"(It stores contents' names of a directory in a dynamic array). There are two issues with this function : (1) It says "Stored file_name" twice for the first file and (2) says "Segmentation fault". I can't figure out either of them. Thanks for your efforts!

#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/types.h>
#include <limits.h>

static short hiddenVisible = 0;

/* Store directory's contents in **contents */
static char ** storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);
/* Count files/directories in a directory */
static unsigned getNumOfContents(struct dirent *dir, DIR *dirp);

int main(int argc, char const *argv[])
{
    char **contents;
    DIR *dirp;
    struct dirent *dir;
    unsigned numOfContents;

    dirp = opendir("/home/gaurav");
    if((dir = readdir(dirp)) == NULL) {
        perror("readdir");
        exit(1);
    }

    /* Getting number of files/directories */
    numOfContents = getNumOfContents(dir, dirp);
    printf("There are %u files.\n", numOfContents);

    /* To position again to the first entry */
    rewinddir(dirp);

    contents = storeContents(dir, dirp, numOfContents);

    /* Print contents */
    for(unsigned i = 0; i < numOfContents; ++i)
        printf("%s\n", contents[i]);

    closedir(dirp);
    return 0;
}

char **
storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents) {

    char **contents;
    unsigned count = 0;

    /* Allocating memory for entries */
    contents = malloc(numOfContents * sizeof(*contents));

    /* Allocating memory for each '*contents' */
    for(unsigned i = 0; i < numOfContents; i++)
        contents[i] = (char *)malloc(NAME_MAX); /* we know char is 1 byte, so no "sizeof" */

    while(count < numOfContents) {
        /* Ignore "." and ".." */
        if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
            if((dir = readdir(dirp)) == NULL) {
                perror("readdir");
                exit(1);
            }
            continue;
        }

        if(hiddenVisible) {
            strcpy(contents[count], dir->d_name);
            if((dir = readdir(dirp)) == NULL) {
                perror("readdir");
                exit(1);
            }
            count++;
        } else {
            if(dir->d_name[0] == '.')
                if((dir = readdir(dirp)) == NULL) {
                    perror("readdir");
                    exit(1);
                }
                else {
                    strcpy(contents[count], dir->d_name);
                    if((dir = readdir(dirp)) == NULL) {
                        perror("readdir");
                        exit(1);
                    }
                    count++;
                }
        }
    }
    return contents;
}

unsigned
getNumOfContents(struct dirent *dir, DIR *dirp) {

    unsigned count = 0;

    while(dir) {
        if(hiddenVisible) {
            /* Ignore "." and ".." */
            if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
                if((dir = readdir(dirp)) == NULL) {
                    perror("readdir a");
                    exit(1);
                }
                continue;
            }
            count++;
            if((dir = readdir(dirp)) == NULL) {
                perror("readdir b");
                exit(1);
            }
        } else {
            if(dir->d_name[0] == '.') {
                if((dir = readdir(dirp)) == NULL) {
                    perror("readdir c");
                    exit(1);
                }
            }
                else {
                    count++;
                    if((dir = readdir(dirp)) == NULL) {
                        perror("readdir d");
                        exit(1);
                    }
                }
        }
    }

    return count;
}
  • Please make a [mcve] or your question will be closed. – P.W May 07 '19 at 07:11
  • I added just one function. I ripped off all the unnecessary stuff. –  May 07 '19 at 07:13
  • And use a debugger to find the line where it segfaults. – klutt May 07 '19 at 07:13
  • You ripped off more than the unnecessary. Create a minimal main function that reproduces the problems. – klutt May 07 '19 at 07:14
  • I added the link. Anyway, let me edit –  May 07 '19 at 07:14
  • Segmentation faults usually occurs when you try to access the memory location that is not available for the user. – Vaibhav May 07 '19 at 07:17
  • @Vaibhav Yeah, I do know that but can't figure out where exactly I am doing that. –  May 07 '19 at 07:18
  • You can either use gdb or put some printf statements to narrow down scope where it is failing. – zero May 07 '19 at 07:22
  • Again, please stop changing the question by fixing the bugs. The point of asking a question here is for others to point out the bugs, so if you change it as you go, you invalidate posted answers. I've done a rollback of your recent edits. – Lundin May 07 '19 at 09:04
  • Yeah I am changing the program, but it didn't work so, I changed the question as well. Anyway it's the third `readdir` in `getNumOfContents()` that fails. Can you help me with that? –  May 07 '19 at 09:24
  • but it was fine before, it's failing after I edited it. –  May 07 '19 at 09:32
  • No, I'm giving up my attempts to salvage this question. Good luck. – Lundin May 07 '19 at 09:34
  • @Lundin It's done mate. Sorry, was quite busy last few days. `readdir()` returns `NULL` when it fails and when the stream is ended as well. The original solution was the **second point** in your answer. –  May 11 '19 at 03:56

2 Answers2

1

contents in the function storeContents is a local copy of contents from main.

Changing it in the function does not change the variable in main.

You should return the array. Change
static void storeContents(struct dirent *dir, DIR *dirp, char **contents, unsigned numOfContents);
to
static char **storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);

,return contents; in the function and call it like char **contents = storeContents(...);

mch
  • 9,424
  • 2
  • 28
  • 42
  • I think I am doing the same you're saying. And btw, control never goes back to `main()`, It all happens inside `storeContents()` –  May 07 '19 at 07:23
  • The variable disappears, but not where it points to, if it is malloced. Like when you return an int, the int is gone, but the value is returned to the caller. – mch May 07 '19 at 07:29
  • @Gaurav This is the reason why. `contents` in main() never gets set, and that's that. Common FAQ, see the linked duplicate. – Lundin May 07 '19 at 07:33
  • @Lundin Please! Just hear me this one time : The control is never returned to `main()`, `segfault` crashes the program when the execution of `storeContents()` is on going. In other words, **It's not that I can't access that memory in `main()`, I can't even access in `storeContents()`, actually I can but just till 4 iterations of the loop.** And even if if I follow your **DUPLICATE OF** suggestion, it doesn't work. Everything is still same. –  May 07 '19 at 08:17
  • @Gaurav You should make that obvious by editing the question then. Like pointing out which line the program crashes on when you run it through your debugger. It seems likely that this program has numerous bugs, we found one of them, might be others. – Lundin May 07 '19 at 08:19
  • @Gaurav I'm guessing readdir is returning NULL but you aren't checking if it was successful. What's the value of `dir` before the program crashes? – Lundin May 07 '19 at 08:26
  • I added the line reference. –  May 07 '19 at 08:42
  • @Gaurav I've re-opened the question. But please note that the bug pointed out definitely needs to be fixed too. – Lundin May 07 '19 at 08:52
  • Okay, thanks. Will do that. Btw, as you asked : `dir` is `4038058936` just before it fails and `4038058968` where it fails. –  May 07 '19 at 08:54
  • @Gaurav You don't need to fix the bugs in the question (that's what it is about), just in the real program :) Anyway I found a second severe bug which is likely the cause, posted an answer. – Lundin May 07 '19 at 08:59
0

Some bugs:

  • contents is a local parameter to the function, it will not get returned to main(). See Dynamic memory access only works inside function.
  • contents = (char **)malloc(numOfContents); is wrong, you need to allocate room for numOfContents pointers. Change this to contents = malloc(numOfContents * sizeof(*contents)).
  • You should check each call to readdir and make sure it doesn't return NULL.
Lundin
  • 195,001
  • 40
  • 254
  • 396