0

I'm developing a little program in ANSI C that generate a graph with dynamics array. When I run it in Visual Studio i get this error: "Program [X] has triggered a breakpoint, and in console is printed: "free Heap block [A] modified at [B] after it was freed". The programs stops on memalloc instruction. I see that this error can occur when memory is freed improperly, but in my case occurs before I call instruction free, and I suppose the problem can be in a wrong memory reallocation.

Code:

    #include "stdafx.h"
    #include <stdlib.h>

    typedef struct TNode TNode;

    struct TNode
    {
        TNode** nodes;
        int nodeCount;
        int index;
    };

    void initialization(int N, TNode * nodes)
    {
        int n = N;
        for (n; n >= 0; --n)
        {
            nodes[n].nodeCount = 0;
            nodes[n].index = n;
        }
    }

    void createGraph(int lastPath, int * J, int * K, TNode * nodes)
    {
        int i = lastPath;
        for (i; i >= 0; --i)
        {
            int nodeJ = J[i];
            int nodeK = K[i];
            //nodeJ
            int lastNode = nodes[nodeJ].nodeCount;
            nodes[nodeJ].nodeCount++;
            if (lastNode == 0)
            {
                nodes[nodeJ].nodes = malloc(sizeof(TNode*) * nodes[nodeJ].nodeCount); //ERROR !!!!
            }
            else
            {
                realloc(nodes[nodeJ].nodes, sizeof(TNode*) * nodes[nodeJ].nodeCount);
            }

            nodes[nodeJ].nodes[lastNode] = &nodes[nodeK];
            //nodeK
            lastNode = nodes[nodeK].nodeCount;
            nodes[nodeK].nodeCount++;
            if (lastNode == 0)
            {
                nodes[nodeK].nodes = malloc(sizeof(TNode*) * nodes[nodeK].nodeCount);
            }
            else
            {
                realloc(nodes[nodeK].nodes, sizeof(TNode*) * nodes[nodeK].nodeCount);
            }
            nodes[nodeK].nodes[lastNode] = &nodes[nodeJ];
        }
    }

    int generate(int J [], int K [], int N){
        int intersections = N + 1;
        TNode *nodes = malloc((intersections) * sizeof(TNode));
        int lastPath = N - 1;
        initialization(N, nodes);
        createGraph(lastPath, J, K, nodes);
        return 0;

    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        int J[8] = { 0, 1, 2, 3, 3, 2, 6, 6 };
        int K[8] = { 1, 2, 3, 4, 5, 6, 8, 7 };
        generate(J, K, 8);

        return 0;
    }

Also I tried to run program on IdeOne: https://ideone.com/fBGEuT and it runs without problem. This makes me suspect that there may be a configuration problem in the compiler.

What do you think is wrong?

trincot
  • 317,000
  • 35
  • 244
  • 286
ununoctio
  • 3
  • 3
  • Could you try to make an [SSCCE](http://sscce.org) that exhibits your problem? – fuz Aug 23 '14 at 12:39
  • Also, please do not cast the result of `malloc` in C. – fuz Aug 23 '14 at 12:40
  • I cast the result because if I compile with visual studio in release mode it gives me an error (Error 1 error C2440: '=' : cannot convert from 'void *' to 'TNode **') – ununoctio Aug 23 '14 at 12:45
  • 2
    That's because you're compiling as C++ instead of C. Please compile as C. The compiler should also give you quite a few warnings, please do not ignore them. – fuz Aug 23 '14 at 12:49
  • 2
    This is a diagnostic that's generated by the debug heap. It is a 100% reliable. Always keep in mind that heap corruption is never detected at the very moment the corruption occurs, it happened earlier. The *next* non-trivial heap operation detects it. Having to rewind the clock is what makes heap corruption debugging difficult. – Hans Passant Aug 23 '14 at 12:51
  • @HansPassant Good thing there are things like Valgrind that make tracking things easier. – fuz Aug 23 '14 at 12:54
  • I solved the cast problem, I had forgotten to set the C compiler in release mode. – ununoctio Aug 23 '14 at 12:57
  • Meanwhile, check your favorite C language book to see what realloc() does. Note how it returns a void*. You cannot ignore that return value in your code. – Hans Passant Aug 23 '14 at 13:01
  • @HansPassant To correct you, you can but you really shouldn't. – fuz Aug 23 '14 at 13:16

1 Answers1

1

This line (and the other realloc-call) is the problem:

realloc(nodes[nodeJ].nodes, sizeof(TNode*) * nodes[nodeJ].nodeCount);

realloc returns a pointer to the enlarged memory area. This memory area might not be the same memory area as the old one. This can happen if there is no space to enlarge the old memory area as another object is just behind it. Please use something like this instead:

nodes[nodeJ].nodes = realloc(nodes[nodeJ].nodes, sizeof(TNode*) * nodes[nodeJ].nodeCount);

You might also want to check for errors as both malloc and realloc may fail.

Your compiler should have emitted a warning for ignoring the result of free. Please do not ignore compiler warnings.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • Thank you, now it works correctly, but the compiler doesn't give my any type of warning. – ununoctio Aug 23 '14 at 13:05
  • @ununoctio Maybe you turned off warnings / didn't turned them on in the first place. Consult your vendor's compiler manual for details on how to turn on warnings. – fuz Aug 23 '14 at 13:15