Home > Blockchain >  How to understand if Heap is full and why malloc keeps return NULL?
How to understand if Heap is full and why malloc keeps return NULL?

Time:03-22

As an exercise, currently I am working on a project: a personal text based database (hence a collection of (personal and not) data arranged in a file as a sort of "database") managed with C programming Language.

I thought to keep all the managing function on a .h file and the main functions (the one that interact with the user, owner of the database) in a .c file. The .h file is not completed yet, but I am slowly testing each function to see if they work correctly.

In particular this one it is daunting me duo to the fact I cannot find the reason why heap gets full (if it really gets full...).

Here is the full code: (The interested function is called "initobj". Though I shared the full code thinking it could be useful to understand)

#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

#if defined(_WIN32)
    #define PATH "C:\\Database\\"
#elif defined(_WIN64)
    #define PATH "C:\\Database\\"
#elif defined(__linux__)
    #define  PATH "/Database/"
#else
    #define PATH NULL
#endif

struct user{
    unsigned int uid;
    char *username;
    char *password;
};

struct file{
    unsigned int uid;
    char *filename;
    char *content;
};

char *initpath(void){
    char filename[] = "Database.txt";
    char *path = (char *)malloc(sizeof(char) * strlen(PATH)   1);
    if(path != NULL){
        strcpy(path, PATH);
        mkdir(path);
        strcat(path, filename);
        return path;
    }
    else
        return NULL;
}

int initobj(struct user *elem, unsigned uid, char *username, char *password){
    elem->uid = uid;
    if((elem->username = (char *)malloc(sizeof(char) * strlen(username)   1)) != NULL)
        strcpy(elem->username, username);
    else
        return -1;
    if((elem->password = (char *)malloc(sizeof(char) * strlen(password)   1)) != NULL)
        strcpy(elem->password, password); //Password is copied into the structure as a normal string. Future updata: encrypting the password
    else
        return -1;
    return 0;
}

int insobj(int database, struct user elem){}

int checkid(int database, unsigned int id){}

int checkusr(int database, char *username){}

int checkpasw(int database, char *password){}

Here instead is the main function code:

#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "database.h"

struct user playground;

int main(int argc, char *argv[]){
    srand(time(0));

    int err;
    struct user *p = &playground;
    char *filepath = initpath();

    if(filepath != NULL && argc == 3){
        if((err = initobj(p, (rand() % 999), argv[1], argv[2])) == 0)
            printf("%u, %s, %s <-  Data inserted.\n", p->uid, p->username, p->password);
        else
            printf("[DEBUG]: From function 'initobj' : %d.\n", err);
    }
    else
        fprintf(stderr, "%s: Not enought arguments.\n", argv[0]);

}

The program keeps return me -1:

C:\Users\Computer\Desktop\ACCESS\Database\lib>dat username password
[DEBUG]: From function 'initobj' : -1. 

Hence means malloc is not able to allocate space in head. I just don't understand why.

CodePudding user response:

At least these issues:

Code fails to allocate sufficient space @ Johnny Mopp

char filename[] = "Database.txt";
char *path = (char *)malloc(sizeof(char) * strlen(PATH)   1); // Wrong size & sense
if(path != NULL){
    strcpy(path, PATH);
    mkdir(path);
    strcat(path, filename); // !! Undefined behavior (UB) !!
    return path;
}

With the UB of strcat(path, filename);, rest of code is irrelevant.

Instead

  • Account for both PATH and filename

  • Cast not needed.

  • Scaling by sizeof(char) * strlen(PATH) 1 should have been sizeof(char) * (strlen(PATH) 1). sizeof(char) is 1 and is not needed either.

    char filename[] = "Database.txt";
    //                     PATH        filename minus its \0   \0
    char *path = malloc(strlen(PATH)   (sizeof filename - 1)   1);
    

mkdir() may fail

Better code would test mkdir() success.

if (mkdir(path)) {
  Handle_failure();
}
  • Related