My program is crashing when it calls `strcpy()' [closed] - c

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.

Related

Understanding malloc with char pointers and strcpy

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.[....]

Run-time error: *** glibc detected *** [closed]

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.

Assigning character to char[x] results in segmentation fault

I have already written a couple of C programs and consider this awkward to ask. But why do I receive a segmentation fault for the following code being supposed to replace "test" by "aaaa"?
#include <stdio.h>
int main(int argc, char* argv[])
{
char* s = "test\0";
printf("old: %s \n", s);
int x = 0;
while(s[x] != 0)
{
s[x++] = 'a'; // segmentation fault here
}
printf("new: %s \n", s); // expecting aaaa
return 0;
}
This assignment is writing to a string literal, which is stored in a read-only section of your executable when it is loaded in memory.
Also, note that the \0 in the literal is redundant.
One way to fix this (as suggested in comments) without copying the string: declare your variable as an array:
char s[] = "test";
This will cause the function to allocate at least 5 bytes of space for the string on the stack, which is normally writeable memory.
Also, you should generally declare a pointer to a string literal as const char*. This will cause the compiler to complain if you try to write to it, which is good, since the system loader will often mark the memory it points to as read-only.
Answering the OP's question in the comment posted to #antron.
What you need is to allocate a character array, then use strcpy() to initialize it with your text, then overwrite with a-s.
Allocation can be done statically (i.e., char s[10];) but make sure the space is enough to store the length of your init string (including the terminating \0).
Alternatively, you can dynamically allocate memory using malloc() and free it using free(). This enables you to allocate exactly enough space to hold your init string (figure it out in run-time using strlen()).

Why is strcpy unsafe in C? [duplicate]

This question already has answers here:
Is the function strcpy always dangerous?
(9 answers)
Closed 8 years ago.
I am a beginner, and I am learning how to copy a string in C now.
Here is a problem I just met:
Every time I try to use "strcpy" command to copy from string 1 to string 2, Visual Studio 2013 will give me an error/warning message saying that "strcpy" is unsafe and suggest me to use strcpy_s instead.
Can you please explain why is strcpy unsafe to use? And what are the safer alternatives to strcpy?
Here is my code:
#include<stdio.h>
#include<string.h>
main()
{
char str1[] = "Copy a string.";
char str2[15];
char str3[15];
int i;
/* with strcpy() */
strcpy(str2, str1);
/* Without strcpy() */
for (i = 0; str1[i]; i++)
str3[i] = str1[i];
str3[i] = '\0';
/* Display str2 and str3 */
printf("The content of str2: %s\n", str2);
printf("The content of str3: %s\n", str3);
return 0;
}
P.S. I am using Visual Studio 2013 64-bit ultimate on Windows 7 64-bit ultimate.
Thank you for your time!
strcpy has no way of knowing how large the destination buffer is (i.e. there is no length parameter) so sloppy programming using it can lead to overrunning the buffer and corrupting other memory. Such an overrun can lead to crashes, odd behaviour and may be exploitable by malware authors.
BTW, look at strncpy that takes a length parameter. One problem to be aware of is that strncpy will not terminate the string if the buffer is too small so it is dangerous in its own way.
In answer to your comment/question - it will depend on context. If you know the buffer is large enough (for example, you allocated it in the previous line at the correct size), use strcpy. If there is any possibility of an overflow then use strncpy and make sure you set the last position in the buffer to null. Note that "any possibility" should be interpreted very generously - unless the previous five or six lines are enough to show safety then use strncpy.
Also see Andon's comment above about strncpy_s. Finally, if you do use strcpy, you might want to add a #pragma to suppress the warning at that location.
Here's your original code:
int main() {
char str1[] = "Copy a string.";
char str2[15];
strcpy(str2, str1);
}
Now, three day later, you go to edit this code. You've realized that you actually need to write the message "This code is copying a string." instead.
int main() {
char str1[] = "This code is copying a string.";
char str2[15];
strcpy(str2, str1);
}
However, you've now accidentally introduced a buffer overflow.
strcpy_s requires the extra argument of the length of str2. This way, while you may not get the whole string into your new buffer, you won't cause undefined behavior.
Unlike strncpy and strcpy_s, strcpy doesn't do any length checking of the destination buffer which may cause stack overflow allowing an attacker to execute malicious code if exploited or just crach your application

Abort instead of segfault with clear memory violation

I came upon this weird behaviour when dealing with C strings. This is an exercise from the K&R book where I was supposed to write a function that appends one string onto the end of another string. This obviously requires the destination string to have enough memory allocated so that the source string fits. Here is the code:
/* strcat: Copies contents of source at the end of dest */
char *strcat(char *dest, const char* source) {
char *d = dest;
// Move to the end of dest
while (*dest != '\0') {
dest++;
} // *dest is now '\0'
while (*source != '\0') {
*dest++ = *source++;
}
*dest = '\0';
return d;
}
During testing I wrote the following, expecting a segfault to happen while the program is running:
int main() {
char s1[] = "hello";
char s2[] = "eheheheheheh";
printf("%s\n", strcat(s1, s2));
}
As far as I understand s1 gets an array of 6 chars allocated and s2 an array of 13 chars. I thought that when strcat tries to write to s1 at indexes higher than 6 the program would segfault. Instead everything works fine, but the program doesn't exit cleanly, instead it does:
helloeheheheheheh
zsh: abort ./a.out
and exits with code 134, which I think just means abort.
Why am I not getting a segfault (or overwriting s2 if the strings are allocated on the stack)? Where are these strings in memory (the stack, or the heap)?
Thanks for your help.
I thought that when strcat tries to write to s1 at indexes higher than 6 the program would segfault.
Writing outside the bounds of memory you have allocated on the stack is undefined behaviour. Invoking this undefined behaviour usually (but not always) results in a segfault. However, you can't be sure that a segfault will happen.
The wikipedia link explains it quite nicely:
When an instance of undefined behavior occurs, so far as the language specification is concerned anything could happen, maybe nothing at all.
So, in this case, you could get a segfault, the program could abort, or sometimes it could just run fine. Or, anything. There is no way of guaranteeing the result.
Where are these strings in memory (the stack, or the heap)?
Since you've declared them as char [] inside main(), they are arrays that have automatic storage, which for practical purposes means they're on the stack.
Edit 1:
I'm going to try and explain how you might go about discovering the answer for yourself. I'm not sure what actually happens as this is not defined behavior (as others have stated), but you can do some simple debugging to figure out what your compiler is actually doing.
Original Answer
My guess would be that they are both on the stack. You can check this by modifying your code with:
int main() {
char c1 = 'X';
char s1[] = "hello";
char s2[] = "eheheheheheh";
char c2 = '3';
printf("%s\n", strcat(s1, s2));
}
c1 and c2 are going to be on the stack. Knowing that you can check if s1 and s2 are as well.
If the address of c1 is less than s1 and the address of s1 is less than c2 then it is on the stack. Otherwise it is probably in your .bss section (which would be the smart thing to do but would break recursion).
The reason I'm banking on the strings being on the stack is that if you are modifying them in the function, and that function calls itself, then the second call would not have its own copy of the strings and hence would not be valid... However, the compiler still knows that this function isn't recursive and can put the strings in the .bss so I could be wrong.
Assuming my guess that it is on the stack is right, in your code
int main() {
char s1[] = "hello";
char s2[] = "eheheheheheh";
printf("%s\n", strcat(s1, s2));
}
"hello" (with the null terminator) is pushed onto the stack, followed by "eheheheheheh" (with the null terminator).
They are both located one after the other (thanks to plain luck of the order in which you wrote them) forming a single memory block that you can write to (but shouldn't!)... That's why there is no seg fault, you can see this by breaking before printf and looking at the addresses.
s2 == (uintptr_t)s1 + (strlen(s1) + 1) should be true if I'm right.
Modifying your code with
int main() {
char s1[] = "hello";
char c = '3';
char s2[] = "eheheheheheh";
printf("%s\n", strcat(s1, s2));
}
Should see c overwritten if I'm right...
However, if I'm wrong and it is in the .bss section then they could still be adjacent and you would be overwriting them without a seg fault.
If you really want to know, disassemble it:
Unfortunately I only know how to do it on Linux. Try using the nm <binary> > <text file>.txt command or objdump -t <your_binary> > <text file>.sym command to dump all the symbols from your program. The commands should also give you the section in which each symbol resides.
Search the file for the s1 and s2 symbols, if you don't find them it should mean that they are on the stack but we will check that in the next step.
Use the objdump -S your_binary > text_file.S command (make sure you built your binary with debug symbols) and then open the .S file in a text editor.
Again search for the s1 and s2 symbols, (hopefully there aren't any others, I suspect not but I'm not sure).
If you find their definitions followed by a push or sub %esp command, then they are on the stack. If you're unsure about what their definitions mean, post it back here and let us have a look.
There's no seg fault or even an overwrite because it can use the memory of the second string and still function. Even give the correct answer. The abort is a sign that the program realized something was wrong. Try reversing the order in which you declare the strings and try again. It probably won't be as pleasant.
int main() {
char s1[] = "hello";
char s2[] = "eheheheheheh";
printf("%s\n", strcat(s1, s2));
}
instead use:
int main() {
char s1[20] = "hello";
char s2[] = "eheheheheheh";
printf("%s\n", strcat(s1, s2));
}
Here is the reason why your program didn't crash:
Your strings are declared as array (s1[] and s2[]). So they're on the stack. And just so happens that memory for s2[] is right after s1[]. So when strcat() is called, all it does is moving each character in s2[] one byte forward. Stack as stack is readable and writable. So there is no restriction what you'e doing.
But I believe the compiler is free to locate s1[] and s2[] where it see fits so this is just a happy accident.
Now to get your program to crash is relatively easy
Swap s1 and s2 in your call: instead of strcat(s1, s2), do strcat(s2, s1). This should cause stack smashing exception.
Change s1[] and s2[] to *s1 and *s2. This should cause segfault when you're writing to readonly segment.
hmm.... the strings are in stack all right since heap is used only for dynamic allocation of memory and stuff..
segfault is for invalid memory access, but with this array you are just writing stuff which is going out of bound (outside the boundry) for the array , so while writing i dont think you will have a issue .... Since in C its actually left to the programer to ensure things are kept in bound for arrays.
Also while reading if you use pointers - I dont think there will be a issue either since you can just continue to read till where ever you want and using the sum of previous lengths. But if you use functions that are mentioned in string.h they relay on the presence of the null character "\0" to decide where to halt the operation -- hence i think your function worked !!
but the termination could also indicate that any other variable / something that might have been present next to the location of the strings might have got over written with char value .... accessing those might have caused the program to exit !!
hope this helps .... good question by the way !

Resources