1

Hey I'm trying to do a simple machine learning application for school but I keep getting double free for some reason I cannot even fathom.

float * evaluate(Network net,float * in)
{
    int i,j;
    float * out;
    Neuron cur_neu;

    for(i=0,j=0;i<net.n_lay;i++) j = net.lay_sizes[i]>j?net.lay_sizes[i]:j; //Calculating the maximum lay size for output storage
    out = (float *) malloc(j*sizeof(float));


    for(i=0;i<net.n_lay;i++)                                                //Cycling through layers
    {
        for(j=0;j<net.lay_sizes[i];j++)                                     //Cycling through Neurons
        {
            cur_neu=net.matrix[i][j];
            out[j] = cur_neu.af(cur_neu.w,in,net.lay_sizes[i-1]);        //Storing each answer in out
        }

        for(j=0;j<net.lay_sizes[i];j++) in[j] = out[j];                     //Transfering answers to in
    }

    return out;
}

float loss(Network net, float **ins_orig, int t_steps)
{
    float **profecies;
    float st = .5f;
    int d_steps = 4;
    int t, i, j;
    int out_size = net.lay_sizes[net.n_lay - 1];
    int in_size = net.lay_sizes[0];
    float out = 0.0f;
    float **ins;
    /*
    d_steps = Divination Steps: Number of time steps forward the network has to predict.
    The size of the output layer must be d_steps*#ins (deconsidering any conceptual i/os) 

    t_steps = Total of Steps: Total number of time steps to simulate.
    */
    //Copying ins
    ins = (float **)malloc(t_steps * sizeof(float *));
    for (i = 0; i < t_steps; i++)  //I allocate memory for and copy ins_orig to ins here
    {
        ins[i] = (float *)malloc(in_size * sizeof(float));
        for (j = 0; j < in_size; j++)
            ins[i][j] = ins_orig[i][j];
    }
    //
    profecies = (float **)malloc(t_steps * sizeof(float *));
    for (t = 0; t < t_steps; t++)
    {
        profecies[t] = evaluate(net, ins[t]);
        /*
        Profecy 0:
        [[a1,b1,c1,d1]
         [e1,f1,g1,h1]
         [i1,j1,k1,l1]]
         Profecy 1:
        [[e2,f2,g2,h2]
         [i2,j2,k2,l2]
         [m2,n2,o2,q2]]

         Verification for:
         t=0:
         loss+= abs(a1-ins[t][0]+b2-ins[t][1]...)
         t=1:
         t=0:
         loss+= abs(e1-ins[t][0]+f2-ins[t][1]...)
        */
        for (i = 0; i < d_steps; i++)      //i is distance of prediction
        {
            if (i <= t)                    // stops negative profecy indexing
            {
                for (j = 0; j < in_size; j++)
                {
                    out += (ins[t][j] - profecies[t-i][j+in_size*i]) * (ins[t][j] - profecies[t-i][j+in_size*i]) * (1 + st*i); //(1+st*i) The further the prediction, the bigger reward
                }
            }
        }
    }
    //Free ins
   
    for (i = 0; i < t_steps; i++)        //I try to free it here, but to no avail
    {
        free(ins[i]);
    }
    free(ins);

    return out;
}

I realize it's probably something very obvious but, I can't figure it out for the life of me and would appreciate the help.

Extra details that probably aren't necessary: evaluate just passes the input to the network (stored in ins) and returns the output both inputs and outputs are stored in float "matrixes"

Edit: Added evaluate

  • 1
    Keep your pointer specifiers anchored to something, not floating in space. `float * * profecies;` should be `float **profecies;` or `float** profecies;`, just pick one. – tadman Mar 24 '21 at 23:45
  • Where does the error occur? – tadman Mar 24 '21 at 23:47
  • 2
    The `free` calls look fine. Maybe the problem is in code that you have not shown. For this reason, all questions asking for debugging help must provide a [complete minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – kaylum Mar 24 '21 at 23:48
  • 1
    Start deleting code until the error goes away, then add it back in slowly until it comes back. Focus on that code. – tadman Mar 24 '21 at 23:49
  • We need to see `evaluate`. Please edit your question and post it – Craig Estey Mar 25 '21 at 00:01
  • @tadman The problem is located in those free() in the for. – Arthur Mograbi Mar 25 '21 at 00:02
  • @CraigEstey done! – Arthur Mograbi Mar 25 '21 at 00:05
  • 1
    What is the exact error you are seeing? You should post diagnostics _verbatim_. Does it perhaps in fact say "double free _or corruption_"? Don't get fixated on the "double free" part and disregard the more likely possibility of _corruption_. Check you have not exceeded the bounds of any of allocated block write accesses - that would cause corruption of the heap management data that `free()` uses to return a block and mark it has free'd. – Clifford Mar 25 '21 at 00:06
  • @tadman ... or use a debugger and get there much faster, checking the indexes of allocated block write accesses. – Clifford Mar 25 '21 at 00:08
  • Everywhere after `free(x);`, do `x = NULL ;` - freeing a NULL pointer is benign. If you still get the error then then the issue is not a double free, but _corruption_. Unfortunately much harder to find, could have occurred anywhere in your code at any time between allocation and free. Check the bounds of write accesses. Consider using Valgrind if using Linux. – Clifford Mar 25 '21 at 00:21
  • 2
    If you are using gcc add `-fsanitize=undefined,address` to your compile - it might notice something. – Jerry Jeremiah Mar 25 '21 at 00:53
  • @Clifford It's easier to find with a debugger, but it's even easier to debug less code. – tadman Mar 25 '21 at 11:28
  • @tadman In some cases that may be true, but removal of code that other code is dependent on changes the behaviour in ways that may look like new bugs. It works for very localised issues, but heap corruption can be caused by any code that accesses the heap anywhere in the entire application. Which code are you going to remove, and have the system remain viable. Also removing code may change what gets corrupted and hide the error, so you think you have found it, but have not. – Clifford Mar 25 '21 at 11:47
  • @Clifford It's just a process of elimination, it's perfectly valid as a debugging strategy. Too many people slam out a whole heap of code and then smack "Compile" as if it will work out just fine. It's better to work incrementally, test as you go. If you've gotten in too deep, peel back a bunch and find a spot you know works, then build back in carefully. This corruption code will quickly reveal itself. – tadman Mar 25 '21 at 11:48
  • @tadman building and testing incrementally is not the same as the divide and conquer strategy you suggested earlier - it is additive, not subtractive. Also heap corruption is particularly tricky in this scenario as I stated. You may be of a different opinion. I am not saying it is not a legitimate strategy, but it is more disruptive. I'd start with the additive development you suggest as a means of avoiding bugs in the first place, then use a debugger to test, verify and debug, then use divide and conquer as a last resort. With good practices, you might not need to resort to that. – Clifford Mar 25 '21 at 11:55
  • @Clifford I'm just suggesting an option, not forcing people to do anything. Not sure why you're so upset about this. – tadman Mar 25 '21 at 11:56
  • 1
    @tadman Me too. I think we are perhaps in violent agreement! You need a toolkit if techniques and strategies. It was not intended as a criticism, rather a matter of considering the non-destructive test before the destructive method. – Clifford Mar 25 '21 at 11:59

1 Answers1

2

In your loss() you allocate the same number of floats for each ins:

ins[i] = (float *)malloc(in_size * sizeof(float));

In your evaluate() you calculate the longest lay_size, indicating that it may NOT be net.lay_sizes[0]:

for(i=0,j=0;i<net.n_lay;i++) j = net.lay_sizes[i]>j?net.lay_sizes[i]:j; //Calculating the maximum lay size for output storage

Then you are writing out-of-bounds here:

for(j=0;j<net.lay_sizes[i];j++) in[j] = out[j];                     //Transfering answers to in

From that point, your memory is corrupted.

Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27