Skip to content

Track bstring/bdestroy #23

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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