c++mallocgoogletestfree

How do I free memory allocated to a void* member of a struct in my c project without breaking my GoogleTest project?


I'm trying to free all the memory allocated in testing_malloc() with the method testing_free(). I am using a Google Test project to test my code and the MemoryLeakDetector mentioned in this answer. However, when I try to free the private_data I get the following heap corruption error.

HEAP CORRUPTION DETECTED: after Normal block (#835) at 0x00000263D9A97F40. CRT detected that the application wrote to memory after end of heap buffer.

testing.h:

#ifndef testing_h
#define testing_h

typedef struct TestStruct {
    void* private_data;
} TestStruct;

void test_method();

int testing_malloc(int input, int is_negative, int length, TestStruct* out);
int testing_free(TestStruct* to_free);
#endif

testing.c:

#include "testing.h"
#include <stdio.h>
#include <malloc.h>
#include <memory.h>

struct TestStruct {
    void* private_data;
};

typedef struct InternalTestStruct {
    int* value_array;
    int* length;
    int* is_negative;
} InternalTestStruct;

int testing_malloc(int input, int is_negative, int length, TestStruct* out)
{
    InternalTestStruct* internaltesting;
    if (input < 0 || input > 9)
    {
        return 1;
    }
    internaltesting = (InternalTestStruct*)malloc(sizeof(TestStruct));
    if (!internaltesting)
    {
        return 2;
    }
    internaltesting->is_negative = (int*)malloc(sizeof(int));
    if (!internaltesting->is_negative)
    {
        free(internaltesting);
        return 2;
    }
    *internaltesting->is_negative = is_negative;
    internaltesting->length = (int*)malloc(sizeof(int));
    if (!internaltesting->length)
    {
        free(internaltesting->is_negative);
        free(internaltesting);
        return 2;
    }
    *internaltesting->length = length;
    internaltesting->value_array = (int*)malloc(sizeof(int) * length);
    if (!(internaltesting->value_array))
    {
        free(internaltesting->length);
        free(internaltesting->is_negative);
        free(internaltesting);
        return 2;
    }
    memset(internaltesting->value_array, 0, sizeof(int) * length);
    internaltesting->value_array[0] = input;
    out->private_data = internaltesting;
    return 0;
}

int testing_free(TestStruct* to_free)
{
    InternalTestStruct* internaltesting = (InternalTestStruct*)to_free->private_data;
    free(internaltesting->value_array);
    free(internaltesting->length);
    free(internaltesting->is_negative);
    /*free(internaltesting);*/
    /*free(to_free->private_data);*/
    return 0;
}

test.cpp

#include "pch.h"
#include "../Testing/testing.h"
#include "../Testing/testing.c"


namespace testns
{

    TEST(construct_tests, construct_zero_does_not_leak) {
        MemoryLeakDetector leakDetector;
        int length = 1;
        int is_negative = 0;
        int expected_value = 0;
        TestStruct* zero = (TestStruct*)malloc(sizeof(void*));
        if (!zero)
        {
            FAIL();
        }
        int result = testing_malloc(expected_value, is_negative, length, zero);
        if (!zero->private_data || result != 0)
        {
            free(zero);
            FAIL();
        }
        testing_free(zero);
        free(zero);
    }
}

pch.h

//
// pch.h
//

#pragma once

#include "gtest/gtest.h"
#include <crtdbg.h>

class MemoryLeakDetector {
public:
    MemoryLeakDetector() {
        _CrtMemCheckpoint(&memState_);
    }

    ~MemoryLeakDetector() {
        _CrtMemState stateNow, stateDiff;
        _CrtMemCheckpoint(&stateNow);
        int diffResult = _CrtMemDifference(&stateDiff, &memState_, &stateNow);
        if (diffResult)
            reportFailure(stateDiff.lSizes[1]);
    }
private:
    void reportFailure(unsigned int unfreedBytes) {
        FAIL() << "Memory leak of " << unfreedBytes << " byte(s) detected.";
    }
    _CrtMemState memState_;
};

I tried both of the commented statements in testing_free but either one gives me the heap corruption message. If I leave them commented, the MemoryLeakDetector correctly reports that I'm leaking memory. I removed the MemoryLeakDetector and uncommented either of the commented statements in testing_free and still got the error.

I did note that I did not receive the exception using a console app to test testing_malloc and testing_free

console.c

#include "testing.h"
#include <stdio.h>
#include <malloc.h>

int main(int charc, char** charv)
{
    int length = 1;
    int is_negative = 0;
    int expected_value = 0;
    int result;
    TestStruct* zero = (TestStruct*)malloc(sizeof(void*));
    if (!zero)
    {
        return 1;
    }
    result = testing_malloc(expected_value, is_negative, length, zero);
    if (!zero->private_data || result != 0)
    {
        free(zero);
        return 1;
    }
    testing_free(zero);
    free(zero);
    return 0;
}

So that leads me to believe that it is an issue with using Google Test. How do I properly free the memory allocated by the following statement without breaking my GoogleTest project?

internaltesting = (InternalTestStruct*)malloc(sizeof(TestStruct));


Solution

  • You call free. The problem isn't how you call free, it's how you called malloc.

    On one type of computer TestStruct is 8 bytes and InternalTestStruct is 24 bytes, so:

    internaltesting = (InternalTestStruct*)malloc(sizeof(TestStruct));
    

    this line allocates 8 bytes, but then you set all 24 bytes as if you had enough space for an InternalTestStruct which you don't. The extra 16 bytes aren't yours. Because you're using some kind of debug mode in your compiler (possibly by default), free checks the bytes before and after what you allocated to make sure you didn't touch them, to help catch bugs. You did touch them, so it caught the bug.

    Solution: allocate the right number of bytes (sizeof(InternalTestStruct))