0
votes

So I searched and looked at all the snprintf(), sprintf() and segmentation fault threads but am still nowhere...

Basically, it seems that the mere presence of a snprintf() statement is causing my code to have a segmentation fault. Long story short, yes, this is for homework...basically, I have to fill in missing code and am under strict orders to not touch the code that already exists. Here's what my code looks like:

        struct dirent* dirEntryPtr;
        struct stat statBuffer;
        char *yourFileName;
        while((dirEntryPtr=readdir(dirPtr))!=NULL)
        {
            int yourFileSize;
            memset(buffer,'\0',sizeof(buffer));
            yourFileName=dirEntryPtr->d_name;
            printf("Directory entry read...%s\n",yourFileName);
            snprintf(buffer,MAX_LINE,"%s/%s",DIR_NAME,yourFileName);
            printf("Printed directory entry to buffer...\n");
            stat(buffer,&statBuffer);
            yourFileSize=statBuffer.st_size;
            printf("File size: %d\n",yourFileSize);
            if(S_ISREG(statBuffer.st_mode))
                {   
                printf("REGULAR!\n");
                snprintf(buffer,MAX_LINE,"%30s (%5d)\n",yourFileName,yourFileSize);
                printf("[%s] %30s (%5d)\n",(char *)statBuffer.st_mode,yourFileName,yourFileSize);
                }
            else
            if(S_ISDIR(statBuffer.st_mode)){
                printf("DIRECTORY!\n");
                snprintf(buffer,MAX_LINE,"%30s (dir)\n",yourFileName);
                printf("[%s] %30s (dir)\n",(char *)statBuffer.st_mode,yourFileName);}
            else
                {
                printf("OTHER!!\n");
                snprintf(buffer,MAX_LINE,"%30s (other)\n",yourFileName);
                printf("[%s] [%s] %30s (other)\n",(char*) S_ISREG(statBuffer.st_mode),(char *)statBuffer.st_mode,yourFileName);
                }                   
            printf("Writing buffer \"%s\" to client...\n",buffer);
            write(clientDescriptor,buffer,MAX_LINE);
            free(buffer);
        }
        close(clientDescriptor);
        exit(EXIT_SUCCESS);

All the printf()s are there basically for debugging. (Yes, I know, use GDB, but I could never figure out how that thing works despite years of instruction!)

Long story short, files in the current directory are read in, one at a time. The first file is usually one called server.c, which is always correctly identified as a "regular" file. However, right when that snprintf() line comes in is where the segmentation fault comes into play. buffer is a string declared (part of the code I'm not allowed to touch, but the instructions were specifically to write the entry to "buffer" using snprintf() -- in fact, the EXACT snprintf() command I'm using is what was given in the instructions!) and set to MAX_LINE bytes (80), which is #defined in an outside header file that's being included. I had a strnlen in there before for debugging purposes to confirm that DIR_NAME is one character and yourFileName, at least in the case of server.c, was 9 -- nowhere near the 80!

I even tried declaring a new variable and just writing one single byte to it via snprintf() but still got the segmentation fault! I've tried both with and without the malloc() command.

What else should I look for??? I did e-mail my professor about this but truth be told I have to submit this, like, TODAY (it's not due for a few more days but I'm going to be out of town) and just need pointers ASAP...but according to what I understand about C, this should work. In fact, it actually WAS working yesterday afternoon but all of a sudden it started segmentation faulting on me late last night. :(

2
Could you please provide a smaller example of the problem if you can reproduce it?Levon
Your example doesn't show how buffer is allocated (if indeed it has been allocated at all).Flexo♦
What is DIR_NAME? Maybe you need to be printing &DIR_NAME :-)azhrei

2 Answers

2
votes

This is a probable cause:

printf("[%s] [%s] %30s (other)\n",
       (char*) S_ISREG(statBuffer.st_mode),
       (char *)statBuffer.st_mode,
       yourFileName);

This instructs printf():

  • to treat the return value of S_ISREG() as a pointer to null terminated string which it is not and will be either 0 or 1 (based on the following yanked from sys/stat.h):

    #define __S_ISTYPE(mode, mask)  (((mode) & __S_IFMT) == (mask))
    
    #define S_ISREG(mode)    __S_ISTYPE((mode), __S_IFREG)
    
  • to treat st_mode as a pointer to a null terminated string which it is not (AFAIK the type of st_mode is an int)

To fix used %d as the format specifier instead of %s OR for S_ISREG() you could use ternary operator and return a string literal instead:

printf("[%s] [%d] %30s (other)\n",
       S_ISREG(statBuffer.st_mode) ? "regular file" : "not regular file",
       statBuffer.st_mode,
       yourFileName);

This is a mistake and almost certaintly the cause:

char buffer[MAX_LINE];

free(buffer);

Only pass to free() what was dynamically allocated:

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

1
votes

Another bug:

write(clientDescriptor,buffer,MAX_LINE);

is almost certainly not what you want if buffer points to a NUL terminated string. This always writes MAX_LINE characters and will not stop at a NUL. I suggest fprintf and friends (puts, fputs) to output strings.