3

Possible Duplicate:
What is the difference between char a[] = “string” and char *p = “string”?

What is the difference between using memcpy on stack memory vs on heap memory? The following code works on Tru64 but segfaults on LINUX

char * string2 = "            ";
(void)memcpy((char *)(string2),(char *)("ALT=---,--"),(size_t)(10));

The second version works on LINUX

char * string2 = malloc(sizeof(char)*12);
(void)memcpy((char *)(string2),(char *)("ALT=---,--"),(size_t)(10));

Can someone explain the segfault on LINUX?

Community
  • 1
  • 1
Alexander Stolz
  • 7,454
  • 12
  • 57
  • 64
  • 1
    Good Read: [What is the difference between char a\[ \] = “string” and char *p = “string”?](http://stackoverflow.com/questions/9460260/what-is-the-difference-between-char-a-string-and-char-p-string) – Alok Save Mar 29 '12 at 10:26
  • 1
    The Stack: Not What You Think It Is. – tbert Mar 29 '12 at 10:48
  • 1
    Your casts are completely abusive and make the code almost impossible to read. None of them is necessary or even useful. Also `sizeof(char)` is defined to be one. `malloc` counts the size to be allocated in terms of sizes of `char`. – Jens Gustedt Mar 29 '12 at 11:34
  • Btw, in the second version that works on Linux, the string pointed to by `string2` is not guaranteed to be nul-terminated after the `memcpy` has finished. That might cause you some problems later. – Steve Jessop Mar 29 '12 at 11:58
  • Just so you know that is not my code so don't blame me for the casts :). I can't say who's code it is but it's from a large safety critical application that I'm porting from tru64 to Linux – Alexander Stolz Mar 29 '12 at 17:07
  • 1
    @Alexander: the code is absurd - it's daft to modify string literals even if the implementation seems to allow it, and anyway why not just write `char *string2 = "ALT=---,--<2 spaces>";`? If the app is safety-critical then you need to look especially carefully at what the effect is on Tru64 of modifying that string literal. The same string literal occurring in different parts of the code can point to the same memory, so it may be (let's hope not) that the original author relies on the `memcpy` to result in another instance of `"<12 spaces>"` somewhere else in the code being suddenly changed! – Steve Jessop Mar 30 '12 at 09:48
  • Sorry about the `<2 spaces>`, `<12 spaces>`. In my browser at least, multiple whitespaces were collapsing, which isn't what I need here... – Steve Jessop Mar 30 '12 at 09:54

7 Answers7

7

The first example has an Undefined Behavior. And so it might work correctly or not or show any random behavior.

Explanation:
The first example, declares a pointer string2to a string literal. String literals are stored in Implementation defined read only memory locations. A user program is not allowed to modify this memory. Any attempt to do so results in Undefined Behavior.

Reference:

C99 standard 6.4.5/5 "String Literals - Semantics":

In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence; for wide string literals, the array elements have type wchar_t, and are initialized with the sequence of wide characters...

It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 1
    In particular, the assumption that the string `" "` is ever stored on the stack is likely false. – caf Mar 29 '12 at 11:40
2

In the first example, you must differ between the pointer and the actual string contents: Although the pointer (string2) is on the stack, the actual string bytes are not. There is a good change that they are in the constants area which is readonly, hence the segfault.

Michael
  • 8,920
  • 3
  • 38
  • 56
2

First of all, the behavior is undefined. From C99, 6.4.5/6:

It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

In practical terms, what happens is that the OS has chosen to load the associated image section in read-only memory; hence the segfault when you try to write.

Jon
  • 428,835
  • 81
  • 738
  • 806
1

In the first example you are not in stack memory but in .rodata (read-only data) section. String literals have static storage duration and are not required to be modifiable.

void foo(void)
{
    // string array has automatic storage duration
    char string[] = "            ";  

    // string2 pointer has automatic storage duration and points to
    // a string literal that a static storage duration
    char *string2 = "            "; // string2 pointer has
}
ouah
  • 142,963
  • 15
  • 272
  • 331
1

In the first case the destination for the memcpy is a string literal, as pointed out by others.

in the second case: Don't cast unnecessary. Avoid magic constants. Sizeof(char) == 1.

#include <stdlib.h>
#include <string.h>

char * string2 = malloc(1+strlen("ALT=---,--"));
(void)memcpy(string2, "ALT=---,--"), 1+strlen("ALT=---,--") );

, which is equivalent to:

char * string2 = malloc(1+strlen("ALT=---,--"));
(void)strcpy(string2, "ALT=---,--") );

BTW: In the original, the constant '10' was too small; the terminating nul byte would not be copied, and the string would be unterminated.

wildplasser
  • 43,142
  • 8
  • 66
  • 109
1

You can try this: char string2[] = " "; (void)memcpy((char *)string2,(char *)("ALT=---,--"),(size_t)(10));

Coaku
  • 977
  • 1
  • 9
  • 23
0

Change your first example to:

char string2 [] = "            ";
(void)memcpy((char *)(string2),(char *)("ALT=---,--"),(size_t)(10));

and then you'll be comparing stack memory versus heap memory.

Dan Moulding
  • 211,373
  • 23
  • 97
  • 98