简体   繁体   中英

Malloc Error Caused by Realloc

I've been scratching my head over this for hours. I'm running Mac OS X 10.8, with XCode 5. I've been getting the following error:

malloc: *** error for object 0x1006487b8: incorrect checksum for freed object - object was            
probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

Unfortunately, object 0x1006487b8 is freed at this point, and my debugger has no recollection of what was there.

The problem is, the error never occurs in the same place. I can only assume that a bit of memory isn't freed properly, and then the computer tries to use it for some other purpose and winds up confused.

My code is using SDL 2, and as far as I can tell, the only free -like function call occurs in the following form with a realloc :

static LGC_Gate* LGC_CreateEmptyGate(){
    if (!gates) {
        gates = malloc(sizeof(LGC_Gate));
        if (!gates)
            return NULL;
    }
    else{
        LGC_Gate* tmpgates = realloc(gates, sizeof(LGC_Gate) * (numgates + 1));
        if (tmpgates)
            gates = tmpgates;
        else
            return NULL;
    }
    numgates++;
    gates[numgates - 1].id = numgates - 1;
    return &(gates[numgates - 1]);
}

gates is a static, file-scope pointer to an array of gates and is declared as such at the top of the file:

static LGC_Gate* gates = NULL;
numgates is initialized to zero at the beginning of the file, and represents the number of gates currently in use. gates should always be of size numgates * sizeof(LGC_Gate) .

My plan was to hold all gates created by the user in a single array, so that it was easy to tally them and get each at a moment's notice. The LGC_CreateEmptyGate function is used like this, for example:

LGC_Gate* LGC_InitActGate(LGC_Action act, uint8_t innum, uint8_t outnum){
    LGC_Gate* product = LGC_CreateEmptyGate();
    if (!product)
        return NULL;

    product->rule.type = LGC_FUNCTION;
    product->rule.act = act;

    product->input.used = innum;
    product->input.val = 0;
    product->output.used = outnum;
    product->output.val = 0;

    int i;
    for (i = 0; i < 8; i++) {
        product->inputfrom[i].active = 0;
    }

    return product;

}

Have I done something horribly wrong?

Update

I have done some debugging with the following code:

printf("%d\n", sizeof(LGC_Gate));
LGC_Gate* TestGates[5];
//Go through the gates, initialize each of them, record the value of their ptr,
//and if any are LESS than sizeof(LGC_Gate) apart, report an error.
int gcount;
for (gcount = 0; gcount < 5; gcount++) {
    TestGates[gcount] = LGC_InitActGate(LGC_NOR, 2, 1);
    printf("%p\n", TestGates[gcount]);
    if (gcount < 4) {
        if (TestGates[gcount] + sizeof(LGC_Gate) > TestGates[gcount + 1]) {
            printf("Error!");
            //TestGates[gcount + 1]->id = 4;  If this line were uncommented, 
            //                                BAD_ACCESS ensues.          
        }
    }
}

To my complete surprise, this actually outputs an error, and indeed crashes on some of the pointers. CORRECTION: The erroring pointer always seems to be the third one. Note that LGC_InitActGate calls LGC_InitEmptyGate once, and simply copies data for the rest of its duration. What is going on?

Update 2

Well, I believe I've discovered the error now. Every time realloc is called, the entire block of memory may or may not relocate, which renders the array of 5 pointers I had useless and pointing to old, freed memory. This makes total sense, but it's one heckuva bug. I should've noticed before. I'm not sure how to fix this, but thanks for the help I got.

What this error is telling you is that the system is about to try and allocate some memory, but when it went to it's free pool, the next available block appears to have been corrupted.

void* p = malloc(100);
free(p);
strcpy(p, "How do you like these apples, malloc?";
p = malloc(100); // <-- crash may happen here, depending on how the free list works.

It is usually the case that the location of the crash is merely the detection and not the cause.

One way you can sometimes track down a crash like this is look at the data at the address (and get lucky and have something recognizable like a string or well known values).

Otherwise, it's time to break out valgrind.

每次从main调用realloc ,内存块可能会或可能不会重定位,这会使数组TestGates拥有指向无效内存的元素。

The code looks fine to me, although it could be simplified since you don't actually need to special-case the starting condition. [Note 1]

Are you certain that you're not holding on to a pointer to a "gate" somewhere in the code? You have to be really careful with auto-reallocating vectors, particularly global ones which might be modified in a function:

LGC_Gate* product = LGC_CreateEmptyGate();
some_innocuous_looking_function();  // Oops, this function calls CreateEmptyGate
product->output.val = some_value;

Note 1: From the Posix realloc specification :

If ptr is a null pointer, realloc() shall be equivalent to malloc() for the specified size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM