Segfault with realloc

2019-08-31 10:04发布

问题:

So I was using malloc in my program and then realloc within a method inside the program. After I called this method so many times I would get a "Segmentation fault (core dumped)".

Upon further inspection I realized that for some reason when my pointer goes from 0x25d7d60 or 0x223fae0 (or any address represented by 7 digits (0xHHHHHHH) ) to 0x7f47d370a010 (with more than 7 digits) for example, a segfault is thrown from within the realloc call, realloc wont even return NULL. I fixed this by simply using malloc and then memcpy instead. However I am very confused at why this happened and wanted to see if any of the users of stackoverflow could shed some light on why this happened.

Thanks

Here is the relevant code:

 unsigned int* myArray;
 unsigned int num_ints;

 int main()
 {

   num_ints = 100; 
   if((myArray =(unsigned int*) malloc(sizeof(unsigned int)*(num_ints)*3))==NULL)
   {
    std::cout << "Malloc failed!" << std::endl;
    return false;
   }

   .
   .
   .

   //This called when n key is pressed (code left out)
   methodName();
 return true;
 }

 void methodName()
 {

 if((myArray =(unsigned int*) realloc(myArray,sizeof(unsigned int)*(num_ints*4)*3))==NULL)
 {
    std::cout << "Realloc failed!" << std::endl;
    exit(0);
 }

 }

回答1:

There's a good chance that, by calling "realloc within a method inside the program", you're actually loading it into a local variable which is then thrown away and your program continues to use the older pointer (which has now been freed).

We would need to see the code to be certain but, in my experience, that's the one of the major causes of allocation errors.


Based on what you've shown, there's nothing wrong with what you're doing. It's effectively the same as this code:

#include <iostream>
#include <cstdlib>
int sz = 1000;
int *buffer = 0;
static int methodName (void) {
    if (sz == 100000)
        sz = 100;
    sz = sz * 10;
    if ((buffer = (int*)realloc (buffer, sz)) == 0) {
        std::cout << "Realloc error" << std::endl;
        return 1;
    }
    return 0;
}
int main(void) {
    int i;
    if ((buffer = (int*)malloc (sz)) == 0) {
        std::cout << "Alloc error" << std::endl;
        return 1;
    }
    for (i = 0; i < 10000000; i++)
        if (methodName() != 0)
            return 1;
    std::cout << "All okay" << std::endl;
    return 0;
}

which works perfectly, doing ten million reallocations.

So the problems lies outside what you've shown us, perhaps a compiler bug (pretty unlikely if you're using a mainstream compiler) or memory corruption from elsewhere in your code.



回答2:

If realloc changes the address of the array, then the myarr in the function scope (local) gets the new value, it does not change the myarr variable in the main

+---------+
| val1    |  = malloc (whatever);    <--------------------------+
+---------+                                                     |
|myarr    |                                                     |
+---------+                                                     |
|addr_main|                                                     |
+----+----+                                                     |
     |                                                          |
     |                                                          |
     |                                                (NO EFFECT on here)
(value of the myaddr 'val1')                                    |
(in main passed by value)                                       |
(to function)                                                   |
     |                                                          |
     +-------+                                                  |
             |                                                  |
             v                                                  |
methodname (myarr, someint)                                     |
             |                                                  |
             |                                                  |
             V                                                  |
        +---------+                                             |
        |  val1   |    = realloc (myarr, whatever)     ---------+
        +---------+    
        |myarr    |    if 'realloc' returns a new address
        +---------+    it will only overwrite 'val1' with some 'val2' 
        |addr_func|    in this LOCAL copy with address 'addr_func' 
        +---------+
             |
             |
             V
     (destroyed after function return)


回答3:

You didn't change myArr in the main scope, realloc maybe return a new address, the old address is invalid.



回答4:

The problem is that your methodName function is assigning the new pointer to it's local copy of myArray.

The quick fix is to make myArray a pointer to a pointer like so:

void methodName(unsigned int **myArray, unsigned int num_ints)
{
    if((*myArray = (unsigned int *)realloc((*myArray), sizeof(unsigned int)*(num_ints*4)*3)) == NULL)
    {
        std::cout << "Realloc failed!" << std::endl;
        exit(0);
    }
}

and then call it by passing the address of myArr:

methodName(&myArr, n_ints);

That way methodName gets the address of the memory of main()s myArr so that it can write into it.

As you can see though, having function parameters that output values can get a little hairy so I suggest instead returning the new address:

unsigned int *methodName(unsigned int *myArray, unsigned int num_ints)
{
    return (unsigned int *)realloc(myArray, sizeof(unsigned int) * (num_ints * 4) *3); 
}

Then it's just a matter of overwriting myArr in main:

myArr = methodName(myArr, n_ints);