0

I wonder why the following code does not throw segmentation fault when a string literal which is a result of dirname() is modified but throws segmentation fault when a string literal created in a usual is modified:

#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>

#define FILE_PATH "/usr/bin/screen"

int main(void)
{
    char db_file[] = FILE_PATH;
    char *filename = dirname(db_file);

    /* no segfault here */
    filename[1] = 'a';

    /* segfault here */
    char *p = "abc";
    p[1] = 'z';
    exit(0);

}

I know that it's an UB to modify a string literal so output I get may be perfectly valid but I wonder if this can be explained. Are string literals that are returned by functions treated differently by compilers? The same situation happens when I compile this code with Clang 3.0 on x86 and gcc on x86 and ARM.

user1042840
  • 1,925
  • 2
  • 16
  • 32

3 Answers3

3

dirname() does not return a reference to a "string" literal, so it is fully legal to modify the data referenced by the pointer returned. Whether to do so makes sense or not is a different question, as the pointer returned may reference the char array passed to dirname().

However, if the OP's code would have passed a "string"-literal to dirname(), this would have already been illegal, as the POSIX specification explicitly state that the function may modify the array passed in.

From the POSIX specifications:

The dirname() function may modify the string pointed to by path.

alk
  • 69,737
  • 10
  • 105
  • 255
2

From the manual

These functions may return pointers to statically allocated memory which may be overwritten by subsequent calls. Alternatively, they may return a pointer to some part of path, so that the string referred to by path should not be modified or freed until the pointer returned by the function is no longer required.

So it might return memory you can modify, and it might not. Depends on your system I guess.

EdgeCaseBerg
  • 2,761
  • 1
  • 23
  • 39
  • Referring UB or not: The data referenced by the returned pointer "*may*" be modifed at any time. Whether this makes sense or not is a different question. – alk Jul 09 '14 at 17:56
  • Ah, I think Joe P's answer and Jonather Leffler's comment are the real reason here. Since the OP is using an array to access when they're not segfaulting, which makes sense. – EdgeCaseBerg Jul 09 '14 at 17:59
  • "So it might return memory you can modify, and it might not" the "might not" bit is incorrect - statically-allocated memory means memory shared across calls. It does not imply read-only memory. – Drew McGowen Jul 09 '14 at 21:10
  • the "may return pointers..." part is what makes me put the might not bit in there, I'm curious if there's a note somewhere that says when that might not be the case – EdgeCaseBerg Jul 09 '14 at 21:21
1

During compilation string literals are stored in a read-only memory segment, and loaded as such at runtime.

This question explains things very nicely:

String literals: Where do they go?

Community
  • 1
  • 1
Joe P
  • 141
  • 6