tags:

views:

76

answers:

2

I am getting the infamous malloc.c:3074 error when running my code (compiles without issue). I compiled using the -g option. I used Valgrind to determine where the memory allocation issue is happening but the results aren't helping a whole lot. Here is the Valgrind output:

==2710== Invalid write of size 8
==2710==    at 0x400FC8: generatePairs (ldbalpha.c:42)
==2710==    by 0x400BFA: main (ldb-stegoencoderalpha.c:53)
==2710==  Address 0x51997c8 is not stack'd, malloc'd or (recently) free'd
==2710== 
==2710== Invalid write of size 8
==2710==    at 0x401047: generatePairs (ldbalpha.c:54)
==2710==    by 0x400BFA: main (ldb-stegoencoderalpha.c:53)
==2710==  Address 0x51997a8 is 0 bytes after a block of size 1,160 alloc'd
==2710==    at 0x4C25153: malloc (vg_replace_malloc.c:195)
==2710==    by 0x400BA6: main (ldb-stegoencoderalpha.c:49)
==2710== 
==2710== Invalid write of size 8
==2710==    at 0x401054: generatePairs (ldbalpha.c:55)
==2710==    by 0x400BFA: main (ldb-stegoencoderalpha.c:53)
==2710==  Address 0x51997b0 is 8 bytes after a block of size 1,160 alloc'd
==2710==    at 0x4C25153: malloc (vg_replace_malloc.c:195)
==2710==    by 0x400BA6: main (ldb-stegoencoderalpha.c:49)
==2710== 
==2710== Invalid write of size 8
==2710==    at 0x401062: generatePairs (ldbalpha.c:56)
==2710==    by 0x400BFA: main (ldb-stegoencoderalpha.c:53)
==2710==  Address 0x51997c0 is not stack'd, malloc'd or (recently) free'd

Here is the main function followed by the called function generatePairs. I listed the line numbers as comments to correspond with the valgrind output:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "ldb.h"

int main(int argc, char * argv[]) {

FILE *pFile;
unsigned char *buffer;
int i, j;
char ch = '\0';
long unsigned int lSize;

if (argc != 3) {
    fprintf(stderr, "Usage: ./ldb-stegoencoderalpha [Stegofile] [messages.txt] >   [messages-encoded.txt]\n");
return 1;
} // end if

pFile = fopen ( argv[1] , "r" );
if (pFile==NULL) {fputs ("File error on arg[1]",stderr); exit (1);}

// obtain file size:
fseek (pFile , 0 , SEEK_END);          // Go to end of File
lSize = ftell (pFile);             // Return # of Bytes in the file
rewind (pFile);               // Rewind to start of file

// allocate memory to contain the whole file:
buffer = malloc(sizeof(char) * lSize+1);     
if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

bitpair * ppairs = malloc(sizeof(bitpair) * (lSize+1));  // Line 49,Structure setup

memset (ppairs, 0, sizeof(bitpair) * (lSize+1));  //zeroize it first

generatePairs(ppairs, lSize+1);  //Line 53 in Valgrind error

After that I do some calculations with those pairs but the Valgrind errors are coming from the generatePairs and malloc functions. Here is the generatePairs function:

#include <string.h>
#include <assert.h>
#include "ldb.h"

void generatePairs(bitpair * ppairs, long unsigned int bits) {

  unsigned int i, rand1, rand2, high, low;
  unsigned int count = 1;

  // initialize the array of pairs
  for(i = 1; i <= bits; i++) {
    bitpair * bp = &ppairs[i];
    bp->ref = -1;
    bp->enc = -1;
    bp->len = -1;
    bp->bit = -1;
    bp->used = 0;
  }

 for(i = 1; i <= bits; i++) {

  rand1 = 0;

  ppairs[rand1].used = 1; 

  rand2 = count;
  count++;

  assert(rand2 <= bits);

  ppairs[rand2].used = 1;         //Line 42 in Valgrind error

  high = rand2;
  low = rand1;

  // initialize both data structures (bp->used is already set)
  bitpair * bp = &ppairs[low];
  bp->ref = low;
  bp->enc = high;
  bp->bit = i;

  bp = &ppairs[high];
  bp->ref = low;      //Line 54 in Valgrind error
  bp->enc = high;     //Line 55 in Valgrind error
  bp->bit = i;        //Line 56 in Valgrind error

  }

return;
}

typedef struct {

long unsigned int ref;
long unsigned int enc;
long unsigned int len;
long unsigned int bit;
long unsigned int used;
 } bitpair;

 void generatePairs(bitpair * ppairs, long unsigned int bits);

Thanks!

+1  A: 

What's the value of rand2 before the assignment? You're likely indexing beyond the allocated memory, thus causing the error.

EDIT: Should you be resetting count each time through your outer for loop? It looks like count will continue to grow beyond what you allocated, causing rand2 to also grow? Eventually, you'll be indexing beyond allocated memory.

lrm
I think you might be right about that nested loop, I dont think I need the do-while anymore. I can just do the rand2 assignment and inc count once for every for-loop.I recompiled and re-ran the program and unfortunately I'm still getting the same heap issue.
Shawn
You start `count` at 1, but you loop `bits` times. `bits` is also how much space you've set aside. If `bits` is 5, and you're inside the loop where `i` is 4, then `count` will be equal to `5`. This places it beyond the range of your allocated memory, thus causing your error.
lrm
Also, why do you continuously initialize the 0th element of the array?
lrm
I found the size error you mention while responding to Jens Gustedt using the assert function (woohoo for a new tool), I now have variable i starting at 1 and going <= bits so it should be .... Wait a second, it should go from 1 to < bits. FOUND THE ERROR THANK YOU
Shawn
+1  A: 

I would:

  • change all your indices and bounds to unsigned instead of int (or even better size_t)
  • put assertions on the indices to ppairs everywhere to check the bounds, something like assert(rand2 < bits) before any ppairs[rand2]
Jens Gustedt
Putting assert(rand2 < bits); gave an assertion error. However, I realized this is because count is initialized to 1 so it will be bigger than bits at the last iteration of the for loop since i starts at 0. So I changed the loops to go from i=1 to i <= bits and the assertion error went away. I've edited the code to reflect this change. The heap error persists.
Shawn
Nice to hear that you found it. Assertions just force you to write down all the assumptions that you usually have. Another implicit assumption you also always carry around is that indices start at 0. Use unsigned in that case. Indices should also be of the correct width for your architecture. Use size_t, really.
Jens Gustedt