16
votes

I saw many questions about getting segmentation fault in C program here in SO, and I thought it would be great to have a reference to those here, a question with some cases that are causing segmentation fault. My answer is posted below.

As written in some answers, the behavior is undefined for all cases, though many people meet them as segmentation fault, so this question is about what causes this "symptom".

In the cases below I get segmentation fault when I run the program, could you determine why?

1)

char *str = "foo";
str[0] = 'b';   // << Segfault hre

2)

char str[] = "foo";
char *newStr = malloc(strlen(str));
strcpy(newStr, str);
free(newStr);   // << Segfault here

3)

char *str = malloc(4 * sizeof(char));
str = "foo";
free(str);      // << Segfault here

4)

char *str = malloc(4 * sizeof(char));
strcpy(str, "foo");
free(str);
if (str != NULL)
    free(str);      // << Segfault here

5)

char *str = "something and then foo";
printf("%s", str[19]);    // << Segfault here

6)

typedef struct {
    char *str;
}st;
...
st *s;
s = malloc(sizeof(st));
s->str = malloc(5);
free(s);
free(s->str);    // << Segfault here
5
Basically, segfaults are caused by use of C. To be fair you get them in other languages too, but not nearly as much.T.E.D.
@T.E.D - this is true, I used C since as you said, it happens much there, and the cases below are of usage of C.MByD
If you intend this to be an instructional question, and you know the answers already, you may as well just post your own answer, and accept it. There's really no need for a million different duplicates of the answer from everyone!Oliver Charlesworth
You're right, I thought I couldn't answer this question for 24 hours or something...MByD
What about the classics: free (0x12345) or maybe strcpy (char*)0x12345, "foo").Paul Beckingham

5 Answers

10
votes

All your examples are causing undefined behaviour, which might lead to a crash (or it might not appear to do any harm at all).

  1. You're not allowed to change a string literal. (see e.g. here)

  2. You forgot to allocate storage for the terminating nul byte, do malloc(strlen(str) + 1);

  3. You're calling free() on a pointer you did not obtain from malloc (or similar functions). As you make the str pointer point to a string literal, you've lost the pointer to the memory allocated with malloc and leak memory here too.

  4. You're calling free() twice on the same pointer, which is undefined behavior.

  5. %s in the printf format string tells printf that the argument is a string (a char * pointing to a sequence of nul terminated characters) You're passing it a char, not a string. If you want to print the suffix of the string use printf("%s", &str[19]);

  6. You're passing in an invalid pointer to free(), you already free'd s, you can't dereference it later when you do s->str. Reverse the order of deallocation: free(s->str); free(s);

5
votes

Case 1:
char *str = "foo"; assign the address of a string in the text segment which is read only, and you can't write to it as done in the second line: str[0] = 'b';. If you want to modify the text, use char str[] = "foo"; which will create an array of chars on the stack and assign its pointer to str.

case 2:
strlen returns the length of the string without the '\0' chracter at the end, so strlen("foo") = 3, while strcpy copies the string including the '\0' character, so it copies more bytes than you allocated.

case 3:
As in case 1, str = "foo"; assigning the address of "foo" to str, this means that you lose the address of the allocated memory and str now contains a pointer to the text segment which you can't free because it's not on the heap, and its a read-only memory.

case 4:
The free function doesn't assign NULL to the pointer received as parameter (since it doesn't have it address, it can't do that). And you are trying to call free on a buffer that was already freed.

case 5:
str[19] is char, not a char pointer, and "%s" expects string, meaning char *. Treated as as an address on many platform, this char is illegal address. printf() doesn't check the arguments received.

case 6:
The usage of s->str after s is freed is wrong. A correct usage will be to first call free(s->str); and then call free(s);. Free the internal allocated memory before freeing its container.

3
votes
  1. Undefined Behaviour: trying to change a string literal
  2. Undefined Behaviour: writing past the end of the array
  3. Undefined Bahaviour: passing to free() a pointer not obtained through malloc()
  4. Undefined Behaviour: passing to free() an invalid pointer
  5. Undefined Behaviour: incompatabilities between the printf() format specifier and actual argument types
  6. Undefined Behaviour: passing to free() an invalid pointer

Undefined Behaviour can manifest itself by a "segmentation fault", but that is by no means a required outcome. Anything could have happened :)

1
votes
  1. You have not allocated any memory. *str is just a pointer.
  2. Reason for the segfault is in line 2, you need to malloc strlen() + 1 because of the string delimiter '\0'
1
votes

3: "foo" is a constant string, not allocated dynamically.

Sidenote: That's a memory leak too.