liballeg/allegro5

memory leak using primitives

Opened this issue · 6 comments

Hi, I hooked Allegro memory allocation to Delphi and discovered a small memory leak using primitives. Here is the code:

var
  MemInterface: ALLEGRO_MEMORY_INTERFACE;
  mem: TDictionary<Pointer, NativeUInt>;

procedure initmem;
begin
  mem := TDictionary<Pointer, NativeUInt>.Create;
end;

procedure donemem;
var
  item: TPair<Pointer, NativeUint>;
begin
  writeln('Dangling allocations: ', mem.Count);

  for item in mem do
  begin
    FreeMem(item.Key);
    WriteLn('Size: ', item.Value, ' bytes');
  end;

  mem.Free;
end;

function MyMalloc(size: NativeUInt; line: Integer; const file_: PAnsiChar; const func: PAnsiChar): Pointer; cdecl;
begin
  Result := AllocMem(size);
  mem.Add(Result, size);
end;

procedure MyFree(ptr: Pointer; line: Integer; const file_: PAnsiChar; const func: PAnsiChar); cdecl;
begin
  mem.Remove(ptr);
  FreeMem(ptr);
end;

function MyRealloc(ptr: Pointer; size: NativeUInt; line: Integer; const file_: PAnsiChar; const func: PAnsiChar): Pointer; cdecl;
begin
  mem.Remove(ptr);
  Result := ReallocMemory(ptr, size);
  mem.Add(Result, size);
end;

function MyCalloc(n: NativeUInt; size: NativeUInt; line: Integer; const file_: PAnsiChar; const func: PAnsiChar): Pointer; cdecl;
begin
  Result := AllocMem(n * size);
  mem.Add(Result, n * size);
end;

procedure Test01();
var
  display: PALLEGRO_DISPLAY;
begin
  if al_install_system(ALLEGRO_VERSION_INT, nil) then
  begin
    al_init_primitives_addon();
    al_set_new_window_title('Allegro');
    al_set_new_display_flags(Ord(ALLEGRO_OPENGL_3_0));
    display := al_create_display(640, 480);
    al_draw_filled_rectangle(0, 0, 100, 100,al_map_rgba(255, 0, 0, 255));
    al_destroy_display(display);
    al_uninstall_system();
  end;
end;

begin
  initmem();
  // Setting up the memory interface with custom functions
  MemInterface.mi_malloc := MyMalloc;
  MemInterface.mi_free := MyFree;
  MemInterface.mi_realloc := MyRealloc;
  MemInterface.mi_calloc := MyCalloc;

  // Apply the custom memory interface to Allegro
  al_set_memory_interface(@MemInterface);

  Test01();

  donemem();
end.

The call to donemem will report and clean up any leaked memory. Test01 is the smallest example to trigger the leak. If you comment out the call the al_draw_filled_rectangle, there will be no leak. Even in a loop, multiple calls to different primiatives, there is only 1 allocation, 56 bytes in size.

The only function call in al_draw_filled_rectangle is to al_draw_prim.

The only function call in al_draw_filled_rectangle is to al_draw_prim.

Nevertheless, memory seems to leak when a primitive routine is called. Comment out the call, no leak.

What happens if you call:

al_free(target);

right before the return ret; in al_draw_prim? Does the leak go away?

What happens if you call:

al_free(target);

right before the return ret; in al_draw_prim? Does the leak go away?

Hi, regrettably, due to the extended period without a response, I was compelled to switch to a different framework to meet a project deadline. My development environment relies heavily on Delphi, necessitating a complex process to compile C code into a DLL and then adapt the headers for Delphi's use. I hope to possibly reconsider allegro in the future.

I had thought about closing this issue earlier but decided against it, recognizing its validity and hoping it might eventually be acknowledged and resolved.

Thank you for your assistance. Currently, I don't have a setup available for testing. This issue was initially reported several months ago, and it's possible that it has since been resolved or perhaps worsened. However, the problem can be readily identified by monitoring allocations and deallocations, which do not align, pinpointing the core issue.

Why don't you test it, @ReiquelApplegate :)

I'm not sure this leak is something we should worry about, since it's small and does not appear to get any bigger with repeated use. I haven't got Windows but there are a few instances in the MacOS code that look like

allegro5/src/macosx/osxgl.m

Lines 2623 to 2632 in c4bc6dc

ALLEGRO_DISPLAY_INTERFACE* _al_osx_get_display_driver(void)
{
static ALLEGRO_DISPLAY_INTERFACE* vt = NULL;
if (vt == NULL) {
vt = al_malloc(sizeof(*vt));
memset(vt, 0, sizeof(ALLEGRO_DISPLAY_INTERFACE));
vt->create_display = create_display;
}
return vt;
}

For sure there is memory allocated to vt which isn't reclaimed, but it is never lost and it never increases.
I suspect this 56 bytes may be something like that.
It would be possible to confirm where it's coming from by making use of the line / file / func parameters to the custom allocation functions. (maybe the test code will have to be rewritten in C first if @jarroddavis68 isn't able to reproduce any more)
Hope that helps.