Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I was experimenting random things to know more about malloc, realloc and free and how they behave when they are used together.
I will include the code and my idea what I was trying to do.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char *str;
/* Initial memory allocation */
str = (char *) malloc(15);
strcpy(str, "63tczfqV4nqB2YnH9iFJbGvGyyDkvK341rrj0G0mo1PEYniOVHejVIFIQnJzHSSMRbuyGMCZ4M5HFMV4y1q4QgYqyxp2XkTjxaolKTkaw1r25S2Emz061tw1");
printf("String = %s, Address = %u\n", str, *str);
/* Reallocating memory */
str = (char *) realloc(str,16);
strcat(str, "12345678");
printf("String = %s, Address = %u\n", str, *str);
free(str);
return 0;
}
I expected my code to behave like this:
I created a character-type memory pointer to point (at max) 15 bytes of memory using malloc.
Using that character pointer, I saved 120 characters using strcpy.
I resized my character pointer to now point (at max) 16 bytes.
I concatenated, using strcat, 8 more characters to that memory buffer which is already holding 120 characters.
Now, my character pointer should point to 128 characters and I tried to reproduce that, however, it failed for 128 characters (but printed the earlier 120 characters which was saved using strcpy).
The exact error was this:
***** glibc detected *** ./a.out: realloc(): invalid next size: 0x0000000001690010 *****
and the console hung on this, i.e., it never moved past realloc line I suppose?
Let's look at the first two lines of your code:
str = (char *) malloc(15);
strcpy(str, "63tczfqV4nqB2YnH9iFJbGvGyyDkvK341rrj0G0mo1PEYniOVHejVIFIQnJzHSSMRbuyGMCZ4M5HFMV4y1q4QgYqyxp2XkTjxaolKTkaw1r25S2Emz061tw1");
At this point, you have broken the rules of the C language. strcpy will write past the end of str which causes undefined behavior.
Everything that happens after this point is kinda up in the air.
Related
I want to write a simple program and I want it to fail to understand strcpy and proper memory management but it still executes. I am trying to dynamically allocate memory (with malloc) for a string enough for only 3 (or anything less than the source) chars to be used as the destination and allocate less memory (or chars) than the string array of the source which is allocated on the stack (string of 10 chars). It copies and prints the content no matter how I define the memory allocation. what's the mistake here?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *ch = NULL;
char name[10] = "something";
ch = (char*)malloc(3 * sizeof(char));
strcpy(ch, name);
printf("%s\n", name);
free(ch);
ch = NULL;
}
The behaviour of writing array out of bounds is undefined. On my computer, without optimization:
% gcc overflow.c
% ./a.out
something
and with optimization enabled
% gcc -O3 overflow.c
In file included from /usr/include/string.h:495,
from overflow.c:2:
In function ‘strcpy’,
inlined from ‘main’ at overflow.c:10:5:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:90:10: warning:
‘__builtin___memcpy_chk’ writing 10 bytes into a region of size 3
overflows the destination [-Wstringop-overflow=]
90 | return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
% ./a.out
*** buffer overflow detected ***: terminated
[2] 240741 abort (core dumped) ./a.out
The reason is that with optimization GCC will actually propagate the array sizes and will produce machine code equivalent to
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char name[10] = "something";
char *ch = malloc(3);
__memcpy_chk(ch, name, sizeof name, 3);
puts(name);
free(ch);
}
and __memcpy_chk will check the length of the destination buffer, and since it is exceeded, the program will abort at runtime.
Always when developing, remember to test your code optimizations enabled too!
The mistake here is you're relying on undefined behaviour.
Compiler does not throw any error for out-of-bound (or invalid) memory access, but when your program try to access an invalid memory, the behaviour is undefined.
For strcpy(), in case the destination buffer is not large enough to hold the content from the source, including the null-terminator, then essentially you'll be accessing memory out of bound, which is invalid, causing the undefined behaviour. It's the responsibility of the programmer to ensure the destination buffer has enough space to store the string to be copied.
From the man page
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy.[....]
This week one problem was discussed by my colleague regarding memory:
Sample code 1:
int main()
{
#define Str "This is String."
char dest[1];
char buff[10];
strncpy(dest, Str, sizeof(Str));
printf("Dest: %s\n", dest);
printf("Buff: %s\n", buff);
}
Output:
Dest: This is String.
Buff: his is String.
Sample Code 2:
int main()
{
#define Str "This is String."
char dest[1];
//char buff[10];
strncpy(dest, Str, sizeof(Str));
printf("Dest: %s\n", dest);
//printf("Buff: %s\n", buff);
}
Output:
Dest: This is String.
*** stack smashing detected ***: ./test terminated
Aborted (core dumped)
I am not understanding why i am getting that output in case 1? as buff is not even used in strncpy, and if i comment variable buff it will give stack smashing detected but with output for dest.
Also for buff why i am getting Output as "his as string."
This is an interesting problem that we all wish to understand at some point or the other. The problem that occurs here is known as “Buffer Overflow”. The side effects of this problem can vary from system to system (also referred as undefined behavior). Just to explain you what might be happening in your case lets assume that the memory layout of the variables in your program is as below
Note above representation is just for understanding and doesn't show actual representation for any architecture.
After the strncpy command is executed the contents of this memory region are as below
Now when you print buff you can see that the start address of buf now has 'h' in it. The printf starts printing this until it finds a null character which is past the buff memory region. Hence you get 'his is String' when you print buf.
However note that program 1 doesn't generate a stack smashing error because of stack guard (which is system/implementation) dependent. So if you execute this code on a system that doesn't include this the Program 1 will also crash (You can test this by increasing Str to a long string).
In case of Program 2 the strncpy just goes past the stack guard over writing the return address from main and hence you get a crash.
Hope this helps.
P.S. All above description is for understanding and doesn't show any actual system representation.
The C Standard specifies strncpy this way:
7.24.2.4 The strncpy function
Synopsis
#include <string.h>
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
Description
The strncpy function copies not more than n characters (characters that follow a null character are not copied) from the array pointed to by s2 to the array pointed to by s1.
If copying takes place between objects that overlap, the behavior is undefined.
If the array pointed to by s2 is a string that is shorter than n characters, null characters are appended to the copy in the array pointed to by s1, until n characters in all have been written.
Returns
The strncpy function returns the value of s1.
These semantics are widely misunderstood: strncpy is not a safe version of strcpy, the destination array is NOT null terminated if the source string is longer than the n argument.
In your example, this n argument is larger than the size of the destination array: the behavior is undefined because characters are written beyond the end of the destination array.
You can observe this is the first example as the buff array is positioned by the compiler just after the end of the dest array in automatic storage (aka on the stack) and is overwritten by strncpy. The compiler could use a different method so the observed behavior is by no means guaranteed.
My advice is to NEVER USE THIS FUNCTION. An opinion shared by other C experts such as Bruce Dawson: Stop using strncpy already!
You should favor a less error-prone function such as this one:
// Utility function: copy with truncation, return source string length
// truncation occurred if return value >= size argument
size_t bstrcpy(char *dest, size_t size, const char *src) {
size_t i;
/* copy the portion that fits */
for (i = 0; i + 1 < size && src[i] != '\0'; i++) {
dest[i] = src[i];
}
/* null terminate destination unless size == 0 */
if (i < size) {
dest[i] = '\0';
}
/* compute necessary length to allow truncation detection */
while (src[i] != '\0') {
i++;
}
return i;
}
You would use it this way in your example:
int main(void) {
#define Str "This is String."
char dest[12];
// the size of the destination array is passed
// after the pointer, just as for `snprintf`
bstrcpy(dest, sizeof dest, Str);
printf("Dest: %s\n", dest);
return 0;
}
Output:
This is a S
strncpy(dest, Str, sizeof(Str));
Your dest is only one byte, so here you are writing in memory which you are not supposed to and this invokes undefined behavior. In other words, anything can happen depending on how compiler implement these things.
The most probable reason for buf getting written is that the compiler places dest after buf. So when you are writing past the boundary of dest you are writing to buf. When you comment out buf it leads to crash.
But as I said before, you may get completely different behavior if a different compiler or even different version of same compiler is used.
Summary: Never do anything that invokes undefined behavior. In strncpy you are supposed to use sizeof(dest), not sizeof(src) and allocate sufficient memory for destination so that data from source is not lost.
The location of the variables on your stack is :-
0. dest
1. buff
12. canary
16. Return address
When buff is present, it protects the canary and return address from damage.
This is undefined behavior (writing more data into dest than fits). The canary has a special random value within it, that is set up when the function starts, and is tested before executing the return instruction. This adds some form of protection to buffer overruns.
Examples of undefined nature, is that the program may have crashed with "illegal instruction # xxxxxx" due to not having a canary.
The program may have behaved normally, if the return address was separate from the variable location.
The stack will typically grow in a negative direction on most current CPUs. Also the location of dest vs buff is compiler dependent. It may have switched them round, or if (for example) you took away the second printf, the compiler may have removed the storage for dest, as it may have decided it was not correctly used.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *str1 = "Bangladesh Bogus Party";
char *str2 = "Sad is a beautiful Country";
strcpy(str1 + 11, str2 + 4);
strcat(str1, "! !! !!!");
printf("\n%s", str1);
return 0;
}
In the code blocks ,it has found....
-------------- Build: Debug in catcpy (compiler: GNU GCC Compiler)---------------
Target is up to date.
Nothing to be done (all items are up-to-date).
-------------- Run: Debug in catcpy (compiler: GNU GCC Compiler)---------------
Checking for existence: E:\Sobar Jonno C (Niton)\String\catcpy\bin\Debug\catcpy.exe
Executing: "C:\Program Files (x86)\CodeBlocks/cb_console_runner.exe" "E:\Sobar Jonno C (Niton)\String\catcpy\bin\Debug\catcpy.exe" (in E:\Sobar Jonno C (Niton)\String\catcpy\.)
You can't overwrite your str1 pointer to a string literal because they are read only memory and your program is trying to write to the memory the pointer points to which causes Undefined Behavior most of the time it causes a Segmentation Fault. And even worst you can't concatenate without previously allocating the necessary space.
If you want your code to work, you need something like this
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[42] = "Bangladesh Bogus Party";
const char *str2 = "Sad is a beautiful country";
strcpy(str1 + 11, str2 + 4);
strcat(str1, "! !! !!!");
printf("%s\n", str1);
return 0;
}
Note that str1 is no longer a string literal, whil str2 is. That is because str2 is never modified, and I added the const specifier to prevent from accidentally doing it. It's impossible to completely prevent this but const can help you notice when you do it unintentionally.
The main issue is that str1 points to a string literal. These live in a read-only section of memory, so attempting to change them will typically cause your program to crash. Rather than defining str1 as a pointer, define it as an array initialized with the literal in question:
char str1[] = "Bangladesh Bogus Party";
If you do this, however, the array doesn't have enough room for the extra characters to be added. So make the array larger so that is has enough space:
char str1[50] = "Bangladesh Bogus Party";
strcpy and strcat both require that the first operand points to memory that is both writable and big enough to hold the result.
In your case neither of these requirements is fulfilled.
String literals are often placed in write-protected memory by the compiler. gcc places string literals in write-protected memory. Other compilers can do it differently.
The problem can be solved by creating str1 in writable memory and increasing its size so that it is big enough to hold the entire string.
The resulting string will be 41 characters + 1 for the string terminator.
Here are a couple of different ways to do it:
char str1[42] = "Bangladesh Bogus Party"; // Declare str1 as an array
or
char *str1 = malloc(42); // Allocate str1 dynamically
strcpy(str1, "Bangladesh Bogus Party"); // and copy the string to it
or
char *str1 = strdup("Bangladesh Bogus Party"); // Allocate str1 dynamically and copy the string to it. It will only be just big enough to hold the initial data
str1 = realloc(str1, 42); // Increase the size to 42.
This question already has answers here:
I can use more memory than how much I've allocated with malloc(), why?
(17 answers)
Closed 8 years ago.
I would expect to see compile errors from this code and perhaps an error when the executable is run. From my understanding, if a pointer is assigned and exists in the heap, and malloc reserves space for the pointer, if what is placed at the pointer is too large, it should start to override code space. However, this runs without issue on Linux 64 bit Ubuntu 14.04.
In this example, I am reserving 5 bytes initially but putting 21 bytes (\0 would be byte 21?) at that memory address. The program runs without issue and the compiler throws no error.
I compiled using the command: "gcc -Wextra -pedantic test.c -o test"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *str;
/* Initial memory allocation */
str = malloc(5);
strcpy(str, "12345678901234567890");
printf("String = %s, Address = %p\n", str, str);
/* Reallocating memory */
str = realloc(str, 26);
strcat(str, "12345");
printf("String = %s, Address = %p\n", str, str);
free(str);
return(0);
}
Malloc will return a block larger than 5 bytes. I am guessing it changes on implementation, but quick google search says 16 bytes.
I would not expect the compiler to produce a compilation error (though maybe a warning?)
In C, it does not give an error or warning if a buffer overflow occurs without adding some sort of bounds checking. Since you are reading and writing to invalid memory, the output of your code is undefined. Sometimes you might be fortunate and get a segmentation fault and you know right away you have an access violation.
You can see that you have invalid reads and writes by running valgrind ./test. I encourage you to familiarize yourself with valgrind as a debugging tool for detecting memory management bugs such as the one you introduced in your code.
Example code:
int main ()
{
char b[] = {"abcd"};
char *c = NULL;
printf("\nsize: %d\n",sizeof(b));
c = (char *)malloc(sizeof(char) * 3);
memcpy(c,b,10); // here invalid read and invalid write
printf("\nb: %s\n",b);
printf("\nc: %s\n",c);
return 0;
}
See in code I have done some invalid reads and invalid writes, but this small program works fine and does not create a core dump.
But once in my big library, whenever I make 1 byte of invalid read or invalid write, it was always creating core dump.
Question:
Why do I sometimes get a core dump from an invalid read/write and sometimes do not get a core dump?
It entirely depends on what you're overwriting or dereferencing when you do an invalid read/write. Specifically, if you're overwriting some pointer that gets dereferenced for example, let's say, the most significant byte of one, you could end up having something get dereferenced to a completely different (and completely invalid) area of memory.
So, for example, if the stack were arranged such that memcpy past the end of c would overwrite part of b, when you attempt to call printf() with b as an argument, it tries to take that pointer and dereference it to print a string. Since it's no longer a valid pointer, that'll cause a segfault. But since things like stack arrangement are platform (and perhaps compiler?) dependent, you may not see the same behavior with similar examples in different programs.
What you are trying to do is basically buffer overflow & in your code sample more specifically heap overflow. The reason you see the crash only at times depends on which memory area you are accessing & if or not you have permission to access/write it (which has been well explained by Dan Fego). I think the example provided by Dan Fego is more about stack overflow (correction welcome!). gcc has protection related to buffer overflow on the stack (stack smashing). You can see this (stack based overflow) in the following example:
#include <stdio.h>
#include <string.h>
int main (void)
{
char b[] = { "abcdefghijk"};
char c [8];
memcpy (c, b, sizeof c + 1); // here invalid read and invalid write
printf ("\nsize: %d\n", sizeof b);
printf ("\nc: %s\n", c);
return 0;
}
Sample output:
$ ./a.out
size: 12
c: abcdefghi���
*** stack smashing detected ***: ./a.out terminated
This protection can be disabled using -fno-stack-protector option in gcc.
Buffer overflow are one of major cause of security vulnerability. Unfortunately function like memcpy do not check for these kinds of problems, but there are ways to protect against these kinds of problems.
Hope this helps!
you create a 3 char string c, but you copy on it 10 chars. it is an error.
it is called a bufferoverflow : you write in a memory that doesnot belong to you. so the behavior is undefined. it could be a crash, it could works fine or it could modify another variable you created.
so the goo thing to do is to allocate enough memory for c to contain the content of b :
c = (char *)malloc(sizeof(char) * (sizeof(b)+1)); // +1 is for the '\0' char that ends every string in c.
2 - when you copy b in c dont forget to put the end of string char : '\0'. it is mandatory in the c standard.
so printf("%s",c); knows where to string finish.
3 - you copied 10 chars from b to c but b containd only 5 chars (a,b,c,d and '\0'), so the behavior of memcpy is undefined (e.g. : memcpy can try to read memory that cant be read,...).
you can copy only the memory you own : the 5 chars of b.
4 - i think the good instruction for defining b is : char b="abcd"; or char b={'a','b','c','d',0};