Home > Software engineering >  Pointer to Struct Value Memory Leak
Pointer to Struct Value Memory Leak

Time:07-30

I am designing an ECS and I have a struct that holds two values: an array of integers and a double pointer. I also have another structure that holds a pointer to the previous struct.

I'm able to access to the pointer to the first struct. However, whenever I try to access any of the pointers in the struct, I end up having a memory leak.

Simple Implementation:

#include <stdio.h>
#include <stdlib.h>
#include "queue.h"

#define MAX_ENTITIES 4096
#define MAX_COMPONENTS 16

typedef unsigned int Entity;
typedef struct ENTITYMANAGER {
  Queue* available;
  unsigned int count;
} ENTITYMANAGER;

typedef void* Component;
typedef struct COMPONENTMANAGER {
  unsigned int* count;
  Component** available;
} COMPONENTMANAGER;

typedef struct COORDINATOR {
  ENTITYMANAGER* entities;
  COMPONENTMANAGER* components;
} COORDINATOR;

typedef struct Test {
  int num;
  char* string;
} Test;

Test* createTestComponent(char* string, int number) {
  Test* test = (Test*) malloc(sizeof(Test));
  test -> num = number;
  test -> string = (string) ? string : "Test Component";
  return test;
}

static ENTITYMANAGER* createEntityManager(void) {
  ENTITYMANAGER* entities = (ENTITYMANAGER*) malloc(sizeof(ENTITYMANAGER));
  entities -> available = queue(MAX_ENTITIES);
  entities -> count = 0;
  return entities;
}

static COMPONENTMANAGER* createComponentManager(void) {
  COMPONENTMANAGER* components = (COMPONENTMANAGER*) malloc(sizeof(COMPONENTMANAGER));
  components -> available = (Component**) malloc(sizeof(Component*) * MAX_ENTITIES);
  for (int element = 0; element < MAX_ENTITIES; element  )
    (components -> available)[element] = (Component*) calloc(MAX_COMPONENTS, sizeof(Component));

  components -> count = (int*) calloc(MAX_ENTITIES, sizeof(int));
  return components;
}

COORDINATOR* init(void) {
  COORDINATOR* coordinator = (COORDINATOR*) malloc(sizeof(COORDINATOR));
  coordinator -> entities = createEntityManager();
  coordinator -> components = createComponentManager();
  return coordinator;
}

Entity createEntity(COORDINATOR* coordinator) {
  if (!(coordinator && (coordinator -> entities -> count < MAX_ENTITIES)))
    return NULL_ITEM;

  Entity entity = front(coordinator -> entities -> available);
    dequeue(coordinator -> entities -> available);
    (coordinator -> entities -> count)  ;

  return entity;
}

void createComponent(COORDINATOR* coordinator, Entity entity, int cnum, void* data) {
  if (!coordinator)
    return;

  (coordinator -> components -> available)[entity][cnum] = createTestComponent(data, 5);
  (coordinator -> components -> count)[entity]  ;
}

int main(int argc, char const *argv[]) {
  COORDINATOR* coordinator = init();

  Entity test = createEntity(coordinator);
  createComponent(coordinator, test, 0, NULL);

  Test* component = (Test*) (coordinator -> components -> available)[test][0];
  printf("Test Component: (\"%s\", %d)", component -> string, component -> num);

  return 0;
}

Queue Implementation: Queue.h

Solution: I had to update my ENTITYMANAGER creation method, which was causing my Entity creation returning an out of bound value causing the memory leak. Specifically, I filled the queue which stores the available entity values with valid values.

static ENTITYMANAGER* createEntityManager(void) {
  ENTITYMANAGER* entities = (ENTITYMANAGER*) malloc(sizeof(ENTITYMANAGER));
  entities -> available = queue(MAX_ENTITIES); entities -> count = 0;
  for (Entity entity = 0; entity < MAX_ENTITIES; entity  )
    enqueue(entities -> available, entity);

  return entities;
}

CodePudding user response:

I suppose there's no memory issue for above code.

I'm just confused you even are not able to access coordinator -> components -> count)[0]. It looks like type of Component is a pointer from (components -> available)[itr][stp] = NULL;. If it's not initialized definitely there will be an error to access it. But there should be no issue to access (coordinator -> components -> count)[0].

CodePudding user response:

That's quite a mouthful, and difficult to understand.

Since it appears that you want an unchanging 'hierarchy' of nested structs, simply declare them that way...

typedef struct {
    int countused;
    int elements[ 128 ];
} Bits_t;

typedef struct {
    int countused;
    Bits_t bits[ 32 ];
} DiffBits_t;

typedef struct {
    int countused;
    DiffBits_t random[ 16 ];
} Outter_t;

void main( void ) {
    Outter_t *topLevel = malloc( sizeof(*topLevel) );

    printf( "%d", sizeof(Outter_t) );

    topLevel->countused = 1;
    topLevel->random[4].countused = 1;
    /* or */
    DiffBits_t *tmp = &topLevel->random[4];
    tmp->countused = 1;
}

Further, use calloc() instead of malloc() and you won't have to zero-out the nested arrays...

  • Related