Why am I getting stack smashing detected when doing memcpy? - c

char test[]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,3);
printf("%s",test);
I'm trying to grasp how exactly memcpy works and this is the example I've written so far.
This gives output as abcdexyz&vjunkcharacters
and the following message.
*** stack smashing detected ***: ./testcode terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7656dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7656d8a]
./testcode[0x8048797]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75704d3]
./testcode[0x80483a1]
What are the reasons behind this situation?

Root Cause:
char test[]={"abcde"};
Allocates enough memory space to store 5 characters only.
memcpy(test+5,test1,3);
Copies the data pointed by test1 beyond the allocated memory space.
Technically, writing beyond the bounds of an allocated memory in this fashion is Undefined Behavior, which means anything can happen.
What actually happens?
What actually happens here is memcpy copies characters beyond the allocated memory thus overwritting the NULL terminator which marks ends of your character array test.
Further, printf reads the contents from starting address of test till it encounters a random NULL thus printing out junk characters.
Solution:
You should ensure that destination buffer has enough memory allocated before you perform the memcpy. Since you intend to copy 3 characters, Your destination buffer test should be atleast:
5 + 3 + 1 byte for NULL terminator = 9 bytes
You can simply use:
char test[9]="abcde";

Your memcpy call does smash the stack, which is why you see that message. You're copying data past the end of your test array, which isn't allowed.

Doing it without an additional buffer
The most straight-forward approach, indeed, would be to avoid the copy:
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
printf("%s%s\n", a, b);
return 0;
}
Doing it with memcpy
memcpy copies n bytes from src to dest. You need to keep track of copying null termination bytes of the strings correctly yourself.
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
/* note that both strings add a '\0' termination */
char c[sizeof(a) + sizeof(b) - 1];
/* copy the content of a to c */
memcpy(c, a, sizeof(a));
/* copy the content of b to where a ends (concatenate the strings) */
memcpy(c + sizeof(a) - 1, b, sizeof(b));
/* note that the '\0' termination of the string is necessary to let
* functions like printf know where the string is over
*/
printf(c);
return 0;
}
Doing it with strcpy and strcat
Note that there's a lot of pitfalls dealing correctly with the null termination of the strings when using memcpy. To simplify this procedure for strings you should do the following.
If these are indeed strings and not random bytes you should stick to the string functions of the standard library. This is how it's done.
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
/* note that both strings add a '\0' termination */
char c[sizeof(a) + sizeof(b) - 1];
/* copy the content of a to c */
strcpy(c, a);
/* copy the content of b to where a ends (concatenate the strings) */
strcat(c, b);
/* note that the '\0' termination of the string is necessary to let
* functions like printf know where the string is over
*/
printf(c);
return 0;
}
On knowing the size of the strings
Concerning knowing the size of the buffer, note that you can usually not simply do sizeof(a_string). If you pass a character array to a function it decays to a pointer and this operation no longer returns the expected size of the array but the size of the pointer.
For strings you need to issue strlen(a_string) which scans for the occurance of the null termination and returns the length of the string (not including the termination).
As for character buffers containing random data (or empty buffers that need to be written to) this approach doesn't work either. You always need to pass the size of the buffer as an additional parameter.

Variable test1 is in memory 4 chars, 3 plus the ending string terminator. Try this:
char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);

The line memcpy(test+5,test1,3); does the following in plain words:
"start at the last element of array "test" and copy 3 characters from array "test1" to there", which basically writes 2 characters beyond the length of the array 'test'.
So if you just want to play around with 'memcpy' define a 3rd array:
char test[]="abcde";
char test1[]="xyz";
char output[sizeof(test) + sizeof(test1)];
memset(output, 0, sizeof(output));
memcpy(&output[0],test,5);
memcpy(&output[5],test1,3);
printf("%s",output);

Related

Copying array in array of pointer to char

I have an char array and I am trying to copy a part of it (tokenization) into 0th index of array of pointer to char using the strncpy function. But during runtime a segmentation fault occurs.
Code example:
char array[30] = "ls -l";
char* args[10];
strncpy(args[0], array + 0, 2);
char *args[10] has the following declaration:
declare args as array 10 of pointer to char
That is to say, we have an array of uninitialized pointers. We'll need to make those pointers point somewhere first, before trying to place characters there. Remembering that we must NUL terminate ('\0') C strings, we can simultaneously allocate and NUL out space for our string by using calloc.
This will make space for just 'l', 's', and our mandatory '\0'.
char original_command[30] = "ls -l";
char *args[10] = { 0 };
args[0] = calloc(3, sizeof (char));
strncpy(args[0], original_command, 2);
Alternatively, we can use malloc, but we must remember the NUL terminating byte.
args[0] = malloc(3);
strncpy(args[0], original_command, 2);
args[0][2] = '\0';
It's generally a good idea to always initialize our variables - see how we initialize our args array to be full of NULL pointers (0). Makes it very clear they don't point anywhere useful yet.
Also note that strncpy does not place a NUL terminating byte if it was not found in the first n bytes of our source string. This is why it's very important to manually terminate our destination string.
Additionally, any call to an *alloc function must be matched later by a call to free, when we are finished using that memory.
/* Do whatever needs to be done */
/* ... */
free(args[0]);
You need to allocate space for the copied string content; char* args[10] reserves only space for holding the pointer to the content, not for the content itself. And don't forget to reserve space for the string terminating character '\0' then.
args[0] = malloc(2+1);
strncpy(agrs[0],array+0,2+1);
agrs[0][2] = '\0';

Allocate memory to a specific "string"

I just started to learn memory management in C, and I didn't understand something. I want to allocate memory to a buffer that holds 12 bytes. which is the exact size of Hello World! without null terminator.
Then I want to append a string to the current string with strcat, and of course I cannot do that because I will get core dumped error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char mystr[12] = "Hello World!";
# allocate memory to mystr?
char *ptr = (char*) malloc(13 * sizeof(char));
strcat(mystr, "Hello");
return 0;
}
So, I don't know how can I allocate memory to the mystr variable if malloc doesn't take any other arguments except the target size.
I don't know how can I allocate memory to the mystr variable if malloc doesn't take any other arguments except the target size.
It is not possible to allocate extra memory to an array. Instead, what you want to do is allocate a new block of memory, copying the original string into the beginning of that memory (strcpy), then append the rest (strcat):
char *p = (char*) malloc((12 + 5 + 1) * sizeof(char));
strcpy(p, myptr);
strcat(p, "Hello");
12 for the first string, plus 5 for the second, plus one for the null-terminator.
Of course, since you know the final size, you could also simply allocate a big enough array instead of using malloc (and you can also use memcpy, too).
The problem should be that a string in C always end with a NULL character (also noted '\0'), so your string is actually 13 characters long. (That character is always automatically added with string literals and serves at telling where the string stops, because a string doesn't have a fixed length.)
So the strcat tries to read the string Hello world! followed by garbage (since the null-terminator is not included in the string).
P.S.: the error is not the core dumped but the Segmentation fault that precedes it, and this tells you that you are trying to change something in a segment you are not supposed to change (or execute/read something you are not supposed to -- this is a security feature).
Edit: after modifying the string mystr, you also need to change the length you allocate (in the malloc: use 13 * sizeof(char), or more simply here in this case sizeof(mystr)).
P.S. 2: also comments in C are started by //, not # (those are preprocessor directives).
you cant change the size of the array. mystr has to be also dynamically allocated.
int main(int argc, char const *argv[])
{
const char *ptr = "Hello World!";
const char *ptr2 = "hello";
char *mystr = malloc(strlen(ptr)+1);
strcpy(mystr, ptr);
mystr = realloc(mystr, strlen(mystr) + strlen(ptr2) + 1);
strcat(mystr, ptr2);
return 0;
}

C - memcpy with char * with length greater than source string length

I have the following code in C now
int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere() // read a string from somewhere
// with length, say 20
memcpy(target_str, source_str, length);
The scenario is that target_str is initialized with 50 bytes. source_str is a string of length 20.
If I want to copy the source_str to target_str i use memcpy() as above with length 50, which is the size of target_str. The reason I use length in memcpy is that, the source_str can have a max value of length but is usually less than that (in the above example its 20).
Now, if I want to copy till length of source_str based on its terminating character ('\0'), even if memcpy length is more than the index of terminating character, is the above code a right way to do it? or is there an alternative suggestion.
Thanks for any help.
The scenario is that target_str is initialized with 50 bytes. source_str is a string of length 20.
If I want to copy the source_str to target_str i use memcpy() as above with length 50, which is the size of target_str.
currently you ask for memcpy to read 30 characters after the end of the source string because it does not care of a possible null terminator on the source, this is an undefined behavior
because you copy a string you can use strcpy rather than memcpy
but the problem of size can be reversed, I mean the target can be smaller than the source, and without protection you will have again a undefined behavior
so you can use strncpy giving the length of the target, just take care of the necessity to add a final null character in case the target is smaller than the source :
int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere(); // length unknown
strncpy(target_str, source_str, length - 1); // -1 to let place for \0
target_str[length - 1] = 0; // force the presence of a null character at end in case
If I want to copy the source_str to target_str i use memcpy() as above
with length 50, which is the size of target_str. The reason I use
length in memcpy is that, the source_str can have a max value of
length but is usually less than that (in the above example its 20).
It is crucially important to distinguish between
the size of the array to which source_str points, and
the length of the string, if any, to which source_str points (+/- the terminator).
If source_str is certain to point to an array of length 50 or more then the memcpy() approach you present is ok. If not, then it produces undefined behavior when source_str in fact points to a shorter array. Any result within the power of your C implementation may occur.
If source_str is certain to point to a (properly-terminated) C string of no more than length - 1 characters, and if it is its string value that you want to copy, then strcpy() is more natural than memcpy(). It will copy all the string contents, up to and including the terminator. This presents no problem when source_str points to an array shorter than length, so long as it contains a string terminator.
If neither of those cases is certain to hold, then it's not clear what you want to do. The strncpy() function may cover some of those cases, but it does not cover all of them.
Now, if I want to copy till length of source_str based on its terminating character ('\0'), even if memcpy length is more than the index of terminating character, is the above code a right way to do it?
No; you'd be copying the entire content of source_str, even past the null-terminator if it occurs before the end of the allocated space for the string it is pointing to.
If your concern is minimizing the auxiliary space used by your program, what you could do is use strlen to determine the length of source_str, and allocate target_str based on that. Also, strcpy is similar to memcpy but is specifically intended for null-terminated strings (observe that it has no "size" or "length" parameter):
char *target_str = NULL;
char *source_str = read_string_from_somewhere();
size_t len = strlen(source_str);
target_str = malloc(len + 1);
strcpy(target_str, source_str);
// ...
free(target_str);
target_str = NULL;
memcpy is used to copy fixed blocks of memory, so if you want to copy something shorter that is terminated by '\n' you don't want to use memcpy.
There is other functions like strncpy or strlcpy that do similar things.
Best to check what the implementations do. I removed the optimized versions from the original source code for the sake of readability.
This is an example memcpy implementation: https://git.musl-libc.org/cgit/musl/tree/src/string/memcpy.c
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
{
unsigned char *d = dest;
const unsigned char *s = src;
for (; n; n--) *d++ = *s++;
return dest;
}
It's clear that here, both pieces of memory are visited for n times. regardless of the size of source or destination string, which causes copying of memory past your string if it was shorter. Which is bad and can cause various unwanted behavior.
this is strlcpy from: https://git.musl-libc.org/cgit/musl/tree/src/string/strlcpy.c
size_t strlcpy(char *d, const char *s, size_t n)
{
char *d0 = d;
size_t *wd;
if (!n--) goto finish;
for (; n && (*d=*s); n--, s++, d++);
*d = 0;
finish:
return d-d0 + strlen(s);
}
The trick here is that n && (*d = 0) evaluates to false and will break the looping condition and exit early.
Hence this gives you the wanted behaviour.
Use strlen to determine the exact size of source_string and allocate accordingly, remembering to add an extra byte for the null terminator. Here's a full example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *source_str = "string_read_from_somewhere";
int len = strlen(source_str);
char *target_str = malloc(len + 1);
if (!target_str) {
fprintf(stderr, "%s:%d: malloc failed", __FILE__, __LINE__);
return 1;
}
memcpy(target_str, source_str, len + 1);
puts(target_str);
free(target_str);
return 0;
}
Also, there's no need to cast the result of malloc. Don't forget to free the allocated memory.
As mentioned in the comments, you probably want to restrict the size of the malloced string to a sensible amount.

How does strcpy() copy a string to an array when you can't change the address of an array?

So basically strcpy assigns the address of the 2nd argument to the 1st, but how does it do it with an array as the first argument? like in my program, i tried changing the address of the array but unfortunately it wont compile. So I had to resort to making a character pointer variable to assign the return value of capitalize. Is there something I'm misunderstanding?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char string[20];
char *Capitalize(char *str)
{
int i;
char *temp;
temp = malloc(sizeof(char)*(int)(strlen(str)+1));
for(i = 0;i < strlen(str);i++)
{
if(*(str+i) >= 'a' && *(str+i)<= 'z')
*(temp+i) = *(str+i) - 32;
else
*(temp+i) = *(str+i);
}
*(temp+i) = '\0';
return temp;
}
int main(void)
{
string word;
printf("Enter word to capitalize: ");
scanf("%19s",word);
word = Capitalize(word);
printf("%s",word);
return 0;
}
strcpy() makes a copy, just like the name implies. it's perfectly legal to copy a string in to an array.
When you make an initialization of an array such as:
char myarr[] = "hello";
You're actually copying the characters into the array.
You seem to be confusing arrays with pointers (see here for some reason you can't treat them the same)
In C, qualifying an array by name without an indexer, is equivalent to specifying a pointer to the memory address of the first element in the array, that is why you can pass as a parameter an array to functions like strcpy.
char * strcpy ( char * destination, const char * source );
strcpy will copy whatever series of characters are found, starting at memory address specified by source, to the memory address specified by destination, until a null character (0) is found (this null character is also copied to the destination buffer).
The address values specified in the parameters are not modified, they just specify from where in memory to copy and where to. It is important that destination is pointing to a memory buffer (can be a char array or a block of memory requested via malloc) with enough capacity for the copied string to fit, otherwise a buffer underrun will occur (you will write characters past the end of your buffer) and your program might crash or behave in a weird way.
Hope I have been clear and not confused you more with my explanation ;)
The thing you seem to be missing is that in c/c++ strings ARE arrays, in most practical respects declaring
char c[] = "hello";
and
char* c = "hello";
is the same thing, all strcpy does is copy the characters into the destination memory, whether that memory is allocated as an array (presumably on the stack) or pointer (presumably on the heap);it does not make a difference.

strcat problem with char *a[10]

include
#include <string.h>
int main()
{
char *array[10]={};
char* token;
token = "testing";
array[0] = "again";
strcat(array[0], token);
}
why it returns Segmentation fault?
I'm a little confused.
Technically, this isn't valid C. (It is valid C++, though.)
char *array[10]={};
You should use
char *array[10] = {0};
This declares an array of 10 pointers to char and initializes them all to null pointers.
char* token;
token = "testing";
This declares token as a pointer to char and points it at a string literal which is non-modifiable.
array[0] = "again";
This points the first char pointer of array at a string literal which (again) is a non-modifiable sequence of char.
strcat(array[0], token);
strcat concatenates one string onto the end of another string. For it to work the first string must be contained in writeable storage and have enough excess storage to contain the second string at and beyond the first terminating null character ('\0') in the first string. Neither of these hold for array[0] which is pointing directly at the string literal.
What you need to do is something like this. (You need to #include <string.h> and <stdlib.h>.)
I've gone for runtime calculation of sizes and dynamic allocation of memory as I'm assuming that you are doing a test for where the strings may not be of known size in the future. With the strings known at compile time you can avoid some (or most) of the work at compile time; but then you may as well do "againtesting" as a single string literal.
char* token = "testing";
char* other_token = "again";
/* Include extra space for string terminator */
size_t required_length = strlen(token) + strlen(other_token) + 1;
/* Dynamically allocated a big enough buffer */
array[0] = malloc( required_length );
strcpy( array[0], other_token );
strcat( array[0], token );
/* More code... */
/* Free allocated buffer */
free( array[0] );
How this works: char *array[10] is an array of 10 char * pointers (basically 10 same things as token).
token = "testing" creates static space somewhere in your program's memory at build time, and puts "testing" there. Then in run time, it puts address to that static "testing" to token.
array[0] = "again" does basically the same thing.
Then, strcat(array[0], token) takes address in array[0], and tries to add token's content to string at that address. Which gives you segfault, since array[0] points to read-only data segment in your memory.
How to do this properly:
char * initial = "first"; // pointer to static "first" string
char * second = "another"; // another one
char string[20]; // local array of 20 bytes
strcpy(string, initial); // copies first string into your read-write memory
strcat(string, second); // adds the second string there
Actually, if you don't want to shoot yourself in the foot, the better way to do something like the last two lines is:
snprintf(string, sizeof(string), "%s%s", initial, second);
snprintf then makes sure that you don't use more than 20 bytes of string. strcat and strcpy would happily go over the limit into invalid memory, and cause another run-time segfault or something worse (think security exploits) if the copied string were longer then the destination space.
To create a array of characters, char *array[10]={}; should instead be char array[10]={};
the segmentation fault occurs because array[0] points to "again", a string literal, and modifying string literals is a no-no(undefined behaviour)
If you're planning on changing the strings involved you should really allocate enough memory for what you need. For example instead of char *token; token = "testing"; you could use, say char token[20] = "testing";, which allows enough room for a 19 character string (plus the null byte at the end).
Similarly, you could use char array[10][20] = {"testing"}; to create an array of 10 strings and set the first one to testing.
You are putting a string at array[0] which is only one character.
Use array[0]='a' like this.

Resources