Skip to content

Track bstring/bdestroy #23

@gwiesenekker

Description

@gwiesenekker

Hi,

I am not sure where to put this. I recently started using bstring and one of the challenges is avoiding memory leaks. I found the following set of macro's and functions useful to track if bstring/bdestroy are balanced. This code is more meant as a template that could be included into a project by updating the various support macro's and functions.

#define PUSH_LEAK(P) push_leak(#P, __FILE__, __FUNC__, __LINE__);

#define POP_LEAK(P) pop_leak(#P, __FILE__, __FUNC__, __LINE__);

#define BSTRING(B)\
  PUSH_LEAK(#B) bstring B; HARDBUG((B = bfromcstr("")) == NULL);

#define BDESTROY(B) POP_LEAK(#B) HARDBUG(bdestroy(B) == BSTR_ERR)

typedef struct
{
  char *ML_name;
  char *ML_file;
  const char *ML_func;
  int ML_line;
  unsigned long ML_pthread_self;
} my_leak_t;

local int nmy_leaks = 0;
local my_leak_t *my_leaks = NULL;

void print_my_leaks(int arg_all)
{
  for (int ileak = nmy_leaks - 1; ileak >= 0; --ileak)
  {
    if (arg_all or (my_leaks[ileak].ML_pthread_self == compat_pthread_self()))
    {
      PRINTF("ileak=%d name=%s file=%s func=%s line=%d pthread_self=%#X\n",
        ileak,
        my_leaks[ileak].ML_name,
        my_leaks[ileak].ML_file,
        my_leaks[ileak].ML_func,
        my_leaks[ileak].ML_line,
        my_leaks[ileak].ML_pthread_self);
    }
  }
}

void push_leak(char *arg_name, char *arg_file, const char *arg_func,
  int arg_line)
{
  HARDBUG(compat_mutex_lock(&my_leak_mutex) != 0)

  if (nmy_leaks >= NMY_LEAKS_MAX)
  {
    PRINTF("PUSH_LEAK name=%s file=%s func=%s line=%d pthread_self=%#X\n",
           arg_name, arg_file, arg_func, arg_line, compat_pthread_self());

    print_my_leaks(FALSE);

    FATAL("TOO MANY PUSH_LEAKS", EXIT_FAILURE)
  }

  my_leaks[nmy_leaks].ML_name = arg_name;
  my_leaks[nmy_leaks].ML_file = arg_file;
  my_leaks[nmy_leaks].ML_func = arg_func;
  my_leaks[nmy_leaks].ML_line = arg_line;
  my_leaks[nmy_leaks].ML_pthread_self = compat_pthread_self();

  nmy_leaks++;

  HARDBUG(compat_mutex_unlock(&my_leak_mutex) != 0)
}

void pop_leak(char *arg_name, char *arg_file, const char *arg_func,
  int arg_line)
{
  HARDBUG(compat_mutex_lock(&my_leak_mutex) != 0)

  if (nmy_leaks == 0)
  {
    PRINTF("POP_LEAK name=%s file=%s func=%s line=%d pthread_self=%#X\n",
           arg_name, arg_file, arg_func, arg_line, compat_pthread_self());

    FATAL("NO PUSHED LEAKS", EXIT_FAILURE)
  }

  int ileak;

  for (ileak = nmy_leaks - 1; ileak >= 0; --ileak)
    if (my_leaks[ileak].ML_pthread_self == compat_pthread_self()) break;

  if (ileak < 0)
  {
    PRINTF("POP_LEAK name=%s file=%s func=%s line=%d pthread_self=%#X\n",
           arg_name, arg_file, arg_func, arg_line, compat_pthread_self());

    print_my_leaks(FALSE);

    FATAL("POP LEAK DID NOT FIND ANY PUSHED LEAKS", EXIT_FAILURE)
  }

  if (strcmp(my_leaks[ileak].ML_name, arg_name) != 0)
  {
    PRINTF("POP_LEAK name=%s file=%s func=%s line=%d pthread_self=%#X\n",
           arg_name, arg_file, arg_func, arg_line, compat_pthread_self());

    print_my_leaks(FALSE);

    FATAL("POP LEAK DID NOT FIND CORRESPONDING PUSH LEAK", EXIT_FAILURE)
  }

  for (int jleak = ileak; jleak < nmy_leaks; jleak++)
    my_leaks[jleak] = my_leaks[jleak + 1];

  nmy_leaks--;

  HARDBUG(compat_mutex_unlock(&my_leak_mutex) != 0)
}

Regards,
GW

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions