0

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;
}
1
  • "I'm assuming". Assuming is not a winning strategy in programming. Problem could be (and is likely to be) in code you have not shown. Please provide complete code as a minimal reproducible example. That is, a small complete example that anyone can take exactly as shown to reproduce the problem - includes code that calls the functions and uses the results in a way the results in the error condition. Commented Jul 29, 2022 at 23:03

2 Answers 2

0

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].

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, you were exactly right. After a bit of testing, I found out that apparently, the issue wasn't my initialization of the pointers but how I was accessing the pointers. The queue I was using to create entities returned an invalid value outside the bounds of all the pointers which caused the leak on runtime.
0

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...

2 Comments

I figured out what was wrong, but thanks for the tip on using calloc() instead of malloc(). I've reimplemented my initialization as seen in the edit.
Glad to help... Caution about using casting (twice) in that printf... The compiler knows the type of all of the nodes in the chain of ->. Imposing 'casting' on the ultimate struct type may lead to heartbreak (hard to find bugs)... Onward and upwanrd

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.