0

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.

user3618656
  • 49
  • 1
  • 7
  • Where does bufSize come from? – this Jun 25 '14 at 00:04
  • Where do all the contents of the `StuffStruct` come from? – AShelly Jun 25 '14 at 00:04
  • `void src*;` should be `void* src;` – Joseph Mark Jun 25 '14 at 00:05
  • The contents of StuffStruct are updated from elsewhere in the code before ExampleFunction is called. Actually, the contents of StuffStruct are being continuously updated, every 1000ms, while the program runs. Also, the segfault only happens when the updates to the data stored in the struct are running at the same time (though again, not every time). – user3618656 Jun 25 '14 at 00:16
  • Please read [Don't cast the result of malloc (and friends)](http://stackoverflow.com/questions/605845). – Deduplicator Jun 25 '14 at 00:18
  • Honestly it sounds like you're having a race condition. You say that structure (and I assume its content) is being updated "elsewhere" and the fault only happens when that update is happing at the "same time". If this is *concurrently* being accessed by a separate thread without so much as a hint of mutual exclusion protection a race condition seems likely. If this *is* in a multi-threaded application, next time kindly include that *very* important detail in the question, as well as the *exact, verbatim* error reported by your *debugger* when the application crashes. – WhozCraig Jun 25 '14 at 00:53
  • The cast is redundant and the code is exactly identical in effect to `memcpy(dest, buf->stuff, buf->bufSize*numStuff);` – M.M Jun 25 '14 at 03:41

2 Answers2

0

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.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
0

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:

  1. 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.

  2. 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.

Jonathan Mayer
  • 1,432
  • 13
  • 17