Why is the result of strcat empty

138 Views Asked by At
char* path = malloc(128);
path = "/bin/"
char* path2 = malloc(128);
path2 = "ls"
strcat(path,path2);
fprintf(stderr, "%s\n",path);

The result is empty.

But if I use

char path[128] = "/bin/";
char* path2 = malloc(128);
path2 = "ls"
strcat(path,path2);
fprintf(stderr, "%s\n",path);

what is the difference between char path[128] and malloc?

3

There are 3 best solutions below

2
On BEST ANSWER

In the below code

char* path = malloc(128);
path = "/bin/";                   //added ;, you're overwriting the returned pointer
char* path2 = malloc(128);
path2 = "ls";                     // same as above
strcat(path,path2);               // the destination buffer is non-modifiable!!
fprintf(stderr, "%s\n",path);

you're essentially overwriting the memory (pointer) returned by allocator function, and making those pointers point to string literal. The strcat() call, thus, invokes undefined behaviour, as the destination buffer is non-modifiable (as they're string literal). This invokes undefined behaviour.

The second snippet is less problematic

char path[128] = "/bin/";   // this is to be used as destination, OK
char* path2 = malloc(128);
path2 = "ls";               // you wouldn't need malloc here            
strcat(path,path2);
fprintf(stderr, "%s\n",path);

here, you're allocating a large enough array (which is modifiable and can be used as a legit destination buffer for strcat()), so from that aspect you're okay. However, for the second argument, you're again overwriting the pointer returned by malloc(), causing memory leak. You don't need to use malloc() here, just assign the literal to the pointer and use that as the second argument in the strcat() call.

0
On

char* does not work like a "string type" in other languages. It is a pointer, so when you write:

char* path = malloc(128);
path = "/bin/"

The memory returned by malloc is leaked since you lost the pointer to it.

Then, when you try to concatenate memory into the memory where the literal "/bin/" was saved, you get undefined behavior since you are trying to modify the memory that backs a string literal.

0
On

Let me annotate these for you...

The first example leaks 256 bytes of memory and may crash, depending on where the constants reside in memory.

// Declare pointer path; malloc 128 bytes of heap memory and assign the address
char* path = malloc(128);
// Reassign the pointer (losing track of the malloc) to a string constant
// (could be in read-only memory if the compiler has deemed it wise)
path = "/bin/";
// Declare pointer path2; malloc 128 bytes of heap memory and assign the address
char* path2 = malloc(128);
// Reassign the pointer (losing track of the malloc) to a string constant
// (could be in read-only memory if the compiler has deemed it wise)
path2 = "ls";
// Attempt to concatenate strings; if `path` resides in read-only memory, this will segfault.
strcat(path, path2);
fprintf(stderr, "%s\n",path);

The second example leaks 128 bytes of memory but should not crash (with these values; with e.g. user input, you'd have to be careful to use strncat).

// Declare pointer path to point to 128 bytes of stack memory (assuming in-function)
// and initialize it to "/bin/"
char path[128] = "/bin/";
// Declare pointer path2; malloc 128 bytes of heap memory and assign the address
char* path2 = malloc(128);
// Reassign the pointer (losing track of the malloc) to a string constant
// (could be in read-only memory if the compiler has deemed it wise)
path2 = "ls";
// Concatenate path2 to path in stack memory; this is fine (but could overflow)
strcat(path, path2);
fprintf(stderr, "%s\n",path);

The correct way would be something like this (if you're not going to return path, which is stack-allocated). This doesn't take care of overflows though.

// Declare pointer path to point to 128 bytes of stack memory (assuming in-function)
// and initialize it to "/bin/"
char path[128] = "/bin/";
// Concatenate the constant "ls" to path in stack memory (could still overflow)
strcat(path, "ls");
fprintf(stderr, "%s\n",path);