0

I'm writing a numpy out of C. I basically assign some attribute from a parent struct to a variable p_ref before I deallocate the parent struct, and then use that variable in a conditional statement later. This causes a core dumped. However, if I don't assign it to the variable but just use the attribute at the end, it does not segfault. I'm confused they seem to be the same. Also, I'm not sure how the second method works because it tries to reference a attribute from an already deallocated struct.

Here is my header for matrix struct:


typedef struct matrix {
    int rows; // number of rows
    int cols; // number of columns
    double* data; // pointer to rows * columns doubles
    int ref_cnt; // How many slices/matrices are referring to this matrix's data
    struct matrix *parent; // NULL if matrix is not a slice, else the parent matrix of the slice
    int is_1d;
    int is_slice;
    int offset;
} matrix;

double rand_double(double low, double high);
void rand_matrix(matrix *result, unsigned int seed, double low, double high);
int allocate_matrix(matrix **mat, int rows, int cols);
int allocate_matrix_ref(matrix **mat, matrix *from, int offset, int rows, int cols);
void deallocate_matrix(matrix *mat);
double get(matrix *mat, int row, int col);
void set(matrix *mat, int row, int col, double val);
void fill_matrix(matrix *mat, double val);
int add_matrix(matrix *result, matrix *mat1, matrix *mat2);
int sub_matrix(matrix *result, matrix *mat1, matrix *mat2);
int mul_matrix(matrix *result, matrix *mat1, matrix *mat2);
int pow_matrix(matrix *result, matrix *mat, int pow);
int neg_matrix(matrix *result, matrix *mat);
int abs_matrix(matrix *result, matrix *mat);

And here are the two versions of my code for deallocating matrix:

Version 1

void deallocate_matrix(matrix *mat) {        
    if (mat == NULL) { return; }
    mat->ref_cnt = mat->ref_cnt - 1;
    if (mat->ref_cnt > 0) { return; }
    int p_ref = mat->parent->ref_cnt;
    if (mat->parent) {
        deallocate_matrix(mat->parent);
    }
    if (!(mat->is_slice) && mat->ref_cnt == 0) {
        free(mat->data);
    } else if (p_ref == 1) {
        free(mat->data);
    }
    free(mat);
    return;
}

Version 2

void deallocate_matrix(matrix *mat) {
    if (mat == NULL) { return; }
    mat->ref_cnt = mat->ref_cnt - 1;
    if (mat->ref_cnt > 0) { return; }
    if (mat->parent) {
        deallocate_matrix(mat->parent);
    }
    if (!(mat->is_slice) && mat->ref_cnt == 0) {
        free(mat->data);
    } else if (mat->parent->ref_cnt == 1) {
        free(mat->data);
    }
    free(mat);
    return;
}
JChang
  • 1
  • *how the second method works because it tries to reference a attribute from an already deallocated struct*. This is called Undefined Behaviour. If you have UB such as accessing freed memory the result is undefined. It means it may crash, it may get wrong values it may even appear to "work". Regardless of the actual behaviour the code is still wrong and cannot be relied on to always "work". [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) – kaylum Apr 25 '21 at 22:06
  • `p_ref` is a **copy** of the original `int` value. There is no accessing of the freed memory when that is used even if the original `mat->parent` has been freed. If you are getting a seg fault it will not be caused by that `p_ref` access. But you don't need to be guessing like this. Do basic debugging - run a program in a debugger and it will tell you instantly and exactly the line of code that triggers the seg fault. – kaylum Apr 25 '21 at 22:13

0 Answers0