I have a global structure:
struct thread_data{
char *incall[10];
int syscall arg_no;
int client_socket;
};
and in main()
char buffer[256];
char *incall[10];
struct thread_data arg_to_thread;
strcpy(incall[0],buffer); /*works fine*/
strcpy(arg_to_thread.incall[0],buffer); /*causes segmentation fault*/
Why does this happen and Please suggest a way out.
thanks
A segfault means that something is wrong. But no segfault does not mean that something isn't wrong. If two situations are basically the same, and one segfaults and the other does not, it usually means that they are both wrong, but only one of them happens to be triggering the segfault.
Looking at the line char* incall[10], what that means is you have an array of 10 pointers to a char. By default, these pointers will be pointing at random places. Therefore, strcpying into incall[0] will be copying the string to a random location. This is most likely going to segfault! You need to initialise incall[0] first (using malloc).
So a bigger question is why doesn't the first line segfault? I would imagine the reason is that it just so happens that whatever was in memory before was a valid pointer. Therefore, the strcpy doesn't segfault, it just overwrites something else which will later cause completely unexpected behaviour. So you must fix both lines of code.
Another issue (once you have fixed that) is that strcpy itself is highly dangerous -- since it copies strings until it finds a 0 byte and then stops, you can never be sure exactly how much it's going to copy (unless you use strlen to allocate the destination memory). So you should use strncpy instead, to limit the number of bytes copied to the size of the buffer.
You've not initialized the pointer incall[0], so goodness only knows where the first strcpy() writes to. You are unlucky that your program does not crash immediately.
You've not initialized the pointer arg_to_thread.incall[0], so goodness only knows where the second strcpy() writes to. You are lucky that your program crashes now, rather than later.
In neither case is it the compiler's fault; you must always ensure you initialize your pointers.
Make sure you have enough memory allocated for your string buffers.
Stay away from strcpy. Use strncpy instead. strcpy is a notorious source of buffer overflow vulnerabilities - a security and maintenance nightmare for which there really isn't an excuse.
Related
I am trying to debug a piece of code written by someone else that results in a segfault sometimes, but not all the time, during a memcpy operation.
Also, I would dearly appreciate it if anyone could give me a hand in translating what's going on in a piece of code that occurs before the memcpy.
First off, we have a function into which is being passed a void pointer and a pointer to a struct, like so:
void ExampleFunction(void *dest, StuffStruct *buf)
The struct looks something like this:
typedef struct {
char *stuff;
unsigned int totalStuff;
unsigned int stuffSize;
unsigned int validStuff;
} StuffStruct;
Back to ExampleFunction. Inside ExampleFunction, this is happening:
void *src;
int numStuff;
numStuff = buf->validStuff;
src = (void *)(buf->stuff);
I'm confused by the above line. What happens exactly when the char array in buf->stuff gets cast to a void pointer, then set as the value of src? I can't follow what is supposed to happen with that step.
Right after this, the memcpy happens:
memcpy(dest, src, buf->bufSize*numStuff)
And that's where the segfault often happens. I've checked for dest/src being null, neither are ever null.
Additionally, in the function that calls ExampleFunction, the array for dest is declared with a size of 5000, if that matters. However, when I printf the value in buf->bufSize*numStuff in the above code, the value is often high above 5000 -- it can go up as high as 80,000 -- WITHOUT segfaulting, though. That is, it runs fine with the length variable (buf->bufSize*numStuff) being much higher than the supposed length that the dest variable was initialized with. However, maybe that doesn't matter since it was cast to a void pointer?
For various reasons I'm unable to use dbg or install an IDE. I'm just using basic printf debugging. Does anyone have any ideas I could explore? Thank you in advance.
First of all, the cast and assignment just copies the address of buf->stuff into the pointer src. There is no magic there.
numStuff = buf->validStuff;
src = (void *)(buf->stuff);
If dest has only enough storage for 5000 bytes, and you are trying to write beyond that length, then you are corrupting your program stack, which can lead to a segfault either on the copy or sometimes a little later. Whether you cast to a void pointer or not makes no difference at all.
memcpy(dest, src, buf->bufSize*numStuff)
I think you need figure out exactly what buf->bufSize*numStuff is supposed to be computing, and either fix it if it is incorrect (not intended), truncate the copy to the size of the destination, or increase the size of the destination array.
A null-pointer dereference is not the only thing that can cause a segfault. When your program allocates memory, it is also possible to trigger a segfault when you attempt to access memory that is after the regions of memory that you have allocated.
Your code looks like it intends to copy the contents of a buffer pointed to by buf->stuff to a destination buffer. If either of those buffers are smaller than the size of the memcpy operation, the memcpy can be overrunning the bounds of allocated memory and triggering a segfault.
Because the memory allocator allocates memory in large chunks, and then divvies it up to various calls to malloc, your code won't consistently fail every time you run past the end of a malloc'ed buffer. You will get exactly the sporadic failure behavior you described.
The assumption that is baked into this code is that both the buffer pointed to by buf->stuff and by the dest pointer are at least "buf->bufSize * numStuff" bytes in length. One of those two assumptions is false.
I would suggest a couple of approaches:
check the code that allocates both the buffer pointed to by dest, and the buffer pointed to by buf->stuff, and ensure that they are always to be as big or larger than buf->bufSize * numStuff.
Failing that, there are a bunch of tools that can help you get better diagnostic information from your program. The simplest to use is efence ("Electric Fence") that will help identify places in your code where you overrun any of your buffers. (http://linux.die.net/man/3/efence). A more thorough analysis can be done using valgrind (http://valgrind.org/) -- but Valgrind is a bit more involved to use.
Good luck!
PS. There's nothing special about casting a char* pointer to a void* pointer -- it's still just an address to an allocated block of memory.
char * a = (char *) malloc(10);
strcpy(a,"string1");
char * x = "string2";
strcat(a,x);
printf("\n%s",a);
Here, I allocated only 10B to a, but still after concatenating a and x (combined size is 16B), C prints the answer without any problem.
But if I do this:
char * a = "string1";
char * x = "string2";
strcat(a,x);
printf("\n%s",a);
Then I get a segfault. Why is this? Why does the first one work despite lower memory allocation? Does strcat reallocate memory for me? If yes, why does the second one not work? Is it because a & x declared that way are unmodifiable string literals?
In your first example, a is allocated in the heap. So when you're concatenating the other string, something in the heap will be overwritten, but there is no write-protection.
In your second example, a points to a region of the memory that contains constants, and is readonly. Hence the seg fault.
The first one doesn't always work, it already caused an overflow. The second one, a is a pointer to the constant string which is stored in the data section, in a read-only page.
In the 2nd case what you have is a pointer to unmodifiable string literals,
In 1st case, you are printing out a heap memory location and in that case its undefined, you cannot guarantee that it will work every time.
(may be write it in a very large loop, yo may see this undefined behavior)
Your code is writing beyond the buffer that it's permitted, which causes undefined behavior. This can work and it can fail, and worse: it can look like it worked but cause seemingly unrelated failures later. The language allows you to do things like this because you're supposed to know what you're doing, but it's not recommended practice.
In your first case, of having used malloc to allocate buffers, you're actually being helped but not in a manner you should ever rely on. The malloc function allocates at least as much space as you've requested, but in practice it typically rounds up to a multiple of 16... so your malloc(10); probably got a 16 byte buffer. This is implementation specific and it's never a good idea to rely on something like that.
In your second case, it's likely that the memory pointed to by your a (and x) variable(s) is non-writable, which is why you've encountered a segfault.
After writing a program to reverse a string, I am having trouble understanding why I got a seg fault while trying to reverse the string. I have listed my program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void reverse(char *);
int main() {
char *str = calloc(1,'\0');
strcpy(str,"mystring0123456789");
reverse(str);
printf("Reverse String is: %s\n",str);
return 0;
}
void reverse(char *string) {
char ch, *start, *end;
int c=0;
int length = strlen(string);
start = string;
end = string;
while (c < length-1){
end++;
c++;
}
c=0;
while(c < length/2){
ch = *end;
*end = *start;
*start = ch;
start++;
end--;
c++;
}
}
1st Question:
Even though I have allocated only 1 byte of memory to the char pointer
str (calloc(1,'\0')), and I copied a 18 bytes string mystring0123456789 into it, and it didn't throw any error and the program worked fine without any SEGFAULT.
Why did my program not throw an error? Ideally it should throw some error as it don't have any memory to store that big string. Can someone throw light on this?
The program ran perfectly and gives me output Reverse String is: 9876543210gnirtsym.
2nd Question:
If the replace the statement
strcpy(str,"mystring0123456789");
with
str="mystring0123456789\0";
the program gives segmentation fault even though I have allocated enough memory for str (malloc(100)).
Why the program throwing segmentation fault?
Even though i have allocated only 1 byte of memory to the char pointer str(calloc(1,'\0')), and i copied a 18 bytes string "mystring0123456789" into it, and it didn't throw any error and the program worked fine without any SEGFAULT.
Your code had a bug -- of course it's not going to do what you expect. Fix the bug and the mystery will go away.
If the replace the statement
strcpy(str,"mystring0123456789");
with
str="mystring0123456789\0";
the program gives segmentation fault even though i have allocated enough memory for str (malloc(100)).
Because when you finish this, str points to a constant. This throws away the previous value of str, a pointer to memory you allocated, and replaces it with a pointer to that constant.
You cannot modify a constant, that's what makes it a constant. The strcpy function copies the constant into a variable which you can then modify.
Imagine if you could do this:
int* h = &2;
Now, if you did *h = 1; you'd be trying to change that constant 2 in your code, which of course you can't do.
That's effectively what you're doing with str="mystring0123456789\0";. It makes str point to that constant in your source code which, of course, you can't modify.
There's no requirement that it throw a segmentation fault. All that happens is that your broken code invokes undefined behavior. If that behavior has no visible effect, that's fine. If it formats the hard drive and paints the screen blue, that's fine too. It's undefined.
You're overwriting the pointer value with the address of a string literal, which totally doesn't use the allocated memory. Then you try to reverse the string literal which is in read-only memory, which causes the segmentation fault.
Your program did not throw an error because, even though you did the wrong thing, ncaught you (more below). You wrote data were you were not supposed to, but you got “lucky” and did not break anything by doing this.
strcpy(str,"mystring0123456789"); copies data into the place where str points. It so happens that, at that place, you are able to write data without causing a trap (this time). In contrast, str="mystring0123456789\0"; changes str to point to a new place. The place it points to is the place where "mystring0123456789\0" is stored. That place is likely read-only memory, so, when you try to write to it in the reverse routine, you get a trap.
More about 1:
When calloc allocates memory, it merely arranges for there to be some space that you are allowed to use. Physically, there is other memory present. You can write to that other memory, but you should not. This is exactly the way things work in the real world: If you rent a hotel room, you are allowed to use that hotel room, but it is wrong for you to use other rooms even if they happen to be open.
Sometimes when you trespass where you are not supposed to, in the real world or in a program, nobody will see, and you will get away with it. Sometimes you will get caught. The fact that you do not get caught does not mean it was okay.
One more note about calloc: You asked it to allocate space for one thing of zero size (the source code '\0' evaluates to zero). So you are asking for zero bytes. Various standards (such as C and Open Unix) may say different things about this, so it may be that, when you ask for zero bytes, calloc gives you one byte. However, it certainly does not give you as many bytes as you wrote with strcpy.
It sounds like you are writing C programs having come from a dynamic language or at least a language that does automatic string handling. For lack of a more formal definition, I find C to be a language very close to the architecture of the machine. That is, you make a lot of the programming decisions. A lot of your program problems are the result of your code causing undefined behavior.You got a segfault with strcpy, because you copied memory into a protected location; the behavior was undefined. Whereas, assigning your fixed string "mystring0123456789\0" was just assigning that pointer to str.
When you implement in C, you decide whether you want to define your storage areas at compile or run-time, or decide to have storage allocated from the heap (malloc/calloc). In either case, you have to write housekeeping routines to make sure you do not exceed the storage you have defined.
Assigning a string to a pointer merely assigns the string's address in memory; it does not copy the string, and a fixed string inside quotes "test-string" is read-only, and you cannot modify it. Your program may have worked just fine, having done that assignment, even though it would not be considered good C coding practice.
There are advantages to handling storage allocations this way, which is why C is a popular language.
Another case is that you can have a segfault when you use memory correct AND your heap became so big that your physical memory cannot manage it (without overlap with stack|text|data|bss -> link)
Proof: link, section Possible Cause #2
Why does the below C code using strcpy work just fine for me? I tried to make it fail in two ways:
1) I tried strcpy from a string literal into allocated memory that was too small to contain it. It copied the whole thing and didn't complain.
2) I tried strcpy from an array that was not NUL-terminated. The strcpy and the printf worked just fine. I had thought that strcpy copied chars until a NUL was found, but none was present and it still stopped.
Why don't these fail? Am I just getting "lucky" in some way, or am I misunderstanding how this function works? Is it specific to my platform (OS X Lion), or do most modern platforms work this way?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *src1 = "123456789";
char *dst1 = (char *)malloc( 5 );
char src2[5] = {'h','e','l','l','o'};
char *dst2 = (char *)malloc( 6 );
printf("src1: %s\n", src1);
strcpy(dst1, src1);
printf("dst1: %s\n", dst1);
strcpy(dst2, src2);
printf("src2: %s\n", src2);
dst2[5] = '\0';
printf("dst2: %s\n", dst2);
return 0;
}
The output from running this code is:
$ ./a.out
src1: 123456789
dst1: 123456789
src2: hello
dst2: hello
First, copying into an array that is too small:
C has no protection for going past array bounds, so if there is nothing sensitive at dst1[5..9], then you get lucky, and the copy goes into memory that you don't rightfully own, but it doesn't crash either. However, that memory is not safe, because it has not been allocated to your variable. Another variable may well have that memory allocated to it, and later overwrite the data you put in there, corrupting your string later on.
Secondly, copying from an array that is not null-terminated:
Even though we're usually taught that memory is full of arbitrary data, huge chunks of it are zero'd out. Even though you didn't put a null-terminator in src2, chances are good that src[5] happens to be \0 anyway. This makes the copy succeed. Note that this is NOT guaranteed, and could fail on any run, on any platform, at anytime. But you got lucky this time (and probably most of the time), and it worked.
Overwriting beyond the bounds of allocated memory causes Undefined Behavior.
So in a way yes you got lucky.
Undefined behavior means anything can happen and the behavior cannot be explained as the Standard, which defines the rules of the language, does not define any behavior.
EDIT:
On Second thoughts, I would say you are really Unlucky here that the program works fine and does not crash. It works now does not mean it will work always, In fact it is a bomb ticking to blow off.
As per Murphy's Law:
"Anything that can go wrong will go wrong"["and most likely at the most inconvenient possible moment"]
[ ]- Is my edit to the Law :)
Yes, you're quite simply getting lucky.
Typically, the heap is contiguous. This means that when you write past the malloced memory, you could be corrupting the following memory block, or some internal data structures that may exist between user memory blocks. Such corruption often manifests itself long after the offending code, which makes debugging this type of bugs difficult.
You're probably getting the NULs because the memory happens to be zero-filled (which isn't guaranteed).
As #Als said, this is undefined behaviour. This may crash, but it doesn't have to.
Many memory managers allocate in larger chunks of memory and then hand it to the "user" in smaller chunks, probably a mutliple of 4 or 8 bytes. So your write over the boundary probably simply writes into the extra bytes allocated. Or it overwrites one of the other variables you have.
You're not malloc-ing enough bytes there. The first string, "123456789" is 10 bytes (the null terminator is present), and {'h','e','l','l','o'} is 6 bytes (again, making room for the null terminator). You're currently clobbering the memory with that code, which leads to undefined (i.e. odd) behavior.
So I've got some C code:
#include <stdio.h>
#include <string.h>
/* putting one of the "char*"s here causes a segfault */
void main() {
char* path = "/temp";
char* temp;
strcpy(temp, path);
}
This compiles, runs, and behaves as it looks. However, if one or both of the character pointers is declared as global variable, strcpy results in a segmentation fault. Why does this happen? Evidently there's an error in my understanding of scope.
As other posters mentioned, the root of the problem is that temp is uninitialized. When declared as an automatic variable on the stack it will contain whatever garbage happens to be in that memory location. Apparently for the compiler+CPU+OS you are running, the garbage at that location is a valid pointer. The strcpy "succeeds" in that it does not segfault, but really it copied a string to some arbitrary location elsewhere in memory. This kind of memory corruption problem strikes fear into the hearts of C programmers everywhere as it is extraordinarily difficult to debug.
When you move the temp variable declaration to global scope, it is placed in the BSS section and automatically zeroed. Attempts to dereference *temp then result in a segfault.
When you move *path to global scope, then *temp moves up one location on the stack. The garbage at that location is apparently not a valid pointer, and so dereferencing *temp results in a segfault.
The temp variable doesn't point to any storage (memory) and it is uninitialized.
if temp is declared as char temp[32]; then the code would work no matter where it is declared. However, there are other problems with declaring temp with a fixed size like that, but that is a question for another day.
Now, why does it crash when declared globally and not locally. Luck...
When declared locally, the value of temp is coming from what ever value might be on the stack at that time. It is luck that it points to an address that doesn't cause a crash. However, it is trashing memory used by someone else.
When declared globally, on most processors these variables will be stored in data segments that will use demand zero pages. Thus char *temp appears as if it was declared char *temp=0.
You forgot to allocate and initialize temp:
temp = (char *)malloc(TEMP_SIZE);
Just make sure TEMP_SIZE is big enough. You can also calculate this at run-time, then make sure the size is enough (should be at least strlen(path))
As mentioned above, you forgot to allocate space for temp.
I prefer strdup to malloc+strcpy. It does what you want to do.
No - this doesn't work regardless of the variables - it just looks like it did because you got (un)lucky. You need to allocate space to store the contents of the string, rather than leave the variable uninitialised.
Uninitialised variables on the stack are going to be pointing at pretty much random locations of memory. If these addresses happen to be valid, your code will trample all over whatever was there, but you won't get an error (but may get nasty memory corruption related bugs elsewhere in your code).
Globals consistently fail because they usually get set to specific patterns that point to unmapped memory. Attempting to dereference these gives you an segfault immediately (which is better - leaving it to later makes the bug very hard to track down).
I'd like to rewrite first Adam's fragment as
// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = '\0';
That way you:
1. don't have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.
The second point is at the loss of the last char of your source string if it is >=256 characters long.
The important part to note:
destination string dest must be large enough to receive the copy.
In your situation temp has no memory allocated to copy into.
Copied from the man page of strcpy:
DESCRIPTION
The strcpy() function copies the string pointed to by src (including
the terminating '\0' character) to the array pointed to by dest. The
strings may not overlap, and the destination string dest must be large
enough to receive the copy.
You're invoking undefined behavior, since you're not initializing the temp variable. It points to a random location in memory, so your program may work, but most likely it will segfault. You need to have your destination string be an array, or have it point to dynamic memory:
// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, 256, path);
// Or, use dynamic memory
char *temp = (char *)malloc(256);
strncpy(temp, 256, path);
Also, use strncpy() instead of strcpy() to avoid buffer overruns.