Home > database >  C malloc works, but it should not
C malloc works, but it should not

Time:11-05

For my linear algebra code I need to allocate memory for a lower triangular matrix, represented by a one dimensional array. I was experimenting with how many elements I can allocate and stumbled upon a weird behaviour. If I set double bottom_row_final to be anything above 240.0, malloc fails and my machine cannot allocate enough memory, but setting it to 410.0, malloc does not fail, and my code crashes later in the for loop when initialising the array after 30 or so iterations (out of bounds indexing excluded as possible error source). Does someone know what is happening here?

//array.c
#include <stdio.h>
#include <stdlib.h>

void vector_alloc(int N, double **pM) {
    if ((*pM = (double *)malloc(N * sizeof(double))) == NULL) {
        printf("Error: malloc failed!\n");
        exit(0);
    }
}

void vector_free(double **pM) {
    free(*pM);
    *pM = NULL;
}

int main(void) {
    //-----------------------------------------------------------------------------------------------------------------------
    double grid_step = 0.0125;
    double bottom_row_final = 410.0;     //  230 works, 240 and above does not allocate anymore, but 410 does 

    int bottom_row_elements = (int)(bottom_row_final / grid_step)   1;
    int lower_triangular_matrix_elements = bottom_row_elements * (bottom_row_elements   1) / 2;
    double *matrix;
    vector_alloc(lower_triangular_matrix_elements, &matrix);
    int index_jumper = 0;
    //-----------------------------------------------------------------------------------------------------------------------  
    for (int i = 0; i <= bottom_row_elements; i  ) {      
        if (i < bottom_row_elements) {
            printf("\n%d\t%d", index_jumper, lower_triangular_matrix_elements - 1);
            matrix[index_jumper] = 1.0;
            printf("\tInitialized with value");
            index_jumper  = (bottom_row_elements - i);
        }
    }
    //-----------------------------------------------------------------------------------------------------------------------  
    vector_free(&matrix);
}

I tried debugging the code and I got segmentation errors (obviously) but malloc should not even be able to allocate the memory for double bottom_row_final above 240.0.

CodePudding user response:

The problem is here:

int lower_triangular_matrix_elements = bottom_row_elements * (bottom_row_elements   1) / 2;

When bottom_row_elements is larger than 46340, the multiplication causes a signed arithmetic overflow, which has undefined behavior. Depending on the actual value, the result may be negative or positive, causing malloc() to either fail because the request is far too large, or to succeed but with an amount of memory that is lower than needed, causing further undefined behavior when accessing beyond the end of the allocated size.

You should use size_t for the computations instead of int.

//array.c
#include <stdio.h>
#include <stdlib.h>

void vector_alloc(size_t N, double **pM) {
    // Allocate the array, initialized to 0.0, assuming IEEE 754 doubles
    if ((*pM = (double *)calloc(N, sizeof(double))) == NULL) {
        printf("Fehler: malloc fehlgeschlagen!\n");
        exit(0);
    }
}

void vector_free(double **pM) {
    free(*pM);
    *pM = NULL;
}

int main(void) {
    //-----------------------------------------------------------------------------------------------------------------------
    double grid_step = 0.0125;
    double bottom_row_final = 410.0;

    size_t bottom_row_elements = (size_t)(bottom_row_final / grid_step)   1;
    size_t lower_triangular_matrix_elements = bottom_row_elements * (bottom_row_elements   1) / 2;
    double *matrix = NULL;
    vector_alloc(lower_triangular_matrix_elements, &matrix);
    size_t index_jumper = 0;
    //-----------------------------------------------------------------------------------------------------------------------  
    for (size_t i = 0; i < bottom_row_elements; i  ) {      
        printf("\n%zu\t%zu",
               index_jumper, lower_triangular_matrix_elements - 1);
        matrix[index_jumper] = 1.0;
        printf("\tInitialized with value");
        index_jumper  = bottom_row_elements - i;
    }
    //-----------------------------------------------------------------------------------------------------------------------  
    vector_free(&matrix);
}

CodePudding user response:

I tried replicating your problem, but I could not. Are you sure that malloc() really worked? Do you get an error message, running it without debug?

  • Related