Author Topic: fontconfig-2.14.2 memory leak.  (Read 790 times)

0 Members and 1 Guest are viewing this topic.

Offline Ed.KloonkTopic starter

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: au
  • Cat video aficionado
fontconfig-2.14.2 memory leak.
« on: March 12, 2023, 10:00:40 am »
Was poking around with some widgets and had a old version of fontconfig that compelled asan to spam the console.

Built the latest version 2.14.2 (with configure flags as mentioned in INSTALL) but still getting mem leaks reported (I believe* in a different function). *forgot to capture the output. Cannot seem to find any free() in the code to match the reported realloc call.

Hurriedly tried just shoving a free() here and there. All I did was manage to keep borking the server until I revert. Ew.

Thought I'd ask on here if anyone can help me spot the obvious. Haven't ruled out my own code yet but showing no symptoms other than this.

Quote
Direct leak of 2560 byte(s) in 4 object(s) allocated from:
    #0 0x4a6508 in __interceptor_realloc ../../../../libsanitizer/asan/asan_malloc_linux.cpp:164
    #1 0x7f630896dfd8 in FcPatternObjectInsertElt /media/sf_VMShare/fontconfig-2.14.2/src/fcpat.c:516

Indirect....etc etc etc etc

fontconfig-2.14.2/src/fcpat.c ( Lines 498-552. Line 516 embolded)
Quote
FcPatternElt *
FcPatternObjectInsertElt (FcPattern *p, FcObject object)
{
    int          i;
    FcPatternElt   *e;

    i = FcPatternObjectPosition (p, object);
    if (i < 0)
    {
   i = -i - 1;

   /* reallocate array */
   if (FcPatternObjectCount (p) + 1 >= p->size)
   {
       int s = p->size + 16;
       if (p->size)
       {
      FcPatternElt *e0 = FcPatternElts(p);
      e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
      if (!e) /* maybe it was mmapped */
      {
          e = malloc(s * sizeof (FcPatternElt));
          if (e)
         memcpy(e, e0, FcPatternObjectCount (p) * sizeof (FcPatternElt));
      }
       }
       else
      e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
       if (!e)
      return FcFalse;
       p->elts_offset = FcPtrToOffset (p, e);
       while (p->size < s)
       {
      e[p->size].object = 0;
      e[p->size].values = NULL;
      p->size++;
       }
   }

   e = FcPatternElts(p);
   /* move elts up */
   memmove (e + i + 1,
       e + i,
       sizeof (FcPatternElt) *
       (FcPatternObjectCount (p) - i));

   /* bump count */
   p->num++;

   e.object = object;
   e.values = NULL;
    }

    return FcPatternElts(p) + i;
}
« Last Edit: March 12, 2023, 10:12:16 am by Ed.Kloonk »
iratus parum formica
 
The following users thanked this post: DiTBho


Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6514
  • Country: fi
    • My home page and email address
Re: fontconfig-2.14.2 memory leak.
« Reply #2 on: March 12, 2023, 02:12:55 pm »
Let's see.

FcPattern is a structure with four members: integers num and size, elts_offset of type intptr_t, and ref of type FcRef AKA int.

FcPatternElt is a structure with two members: object (of type FcObject AKA int), and a pointer values (to type FcValueList) forming a linked list.

FcPatternElts(p) evaluates to ((FcPatternElt *)((intptr_t)p + (ptrdiff_t)(p->elts_offset))), i.e. elts = (FcPatternElt *)((char *)p + p->elts_offset).

Looking at other related stuff, that points to an array of objects at byte offset elts_offset relative to the original pointer, sorted in order of increasing object (number identifier).

In FcPatternObjectInsertElt(), FcPatternObjectPosition() does a binary search to find the specified object.  If the object is found, FcPatternObjectInsertElt() returns a pointer to it.  Otherwise, we get into the if body.

FcPatternObjectCount(p) returns just p->num, the number of FcPatternElt's in the array, and obviously p->size is the size of the array.

Now, how is that reallocation supposed to work?  Ah yes, that aforementioned FcPatternElts(), although relative to the original pointer, may actually be a completely separate pointer.  The line 528, p->elts_offset = FcPtrToOffset (p, e);, evaluates to p->elts_offset = (intptr_t)e - (intptr_t)p;, so that FcPatternElts() will yield the possibly realloc()'d pointer.

The FcPatternObjectInsertElt() is used in src/fcpat.c:FcPatternObjectListAdd(), src/fcpat.c:FcPatternObjectAddWithBinding(), and src/fccfg.c:FcConfigPatternAdd().

If we look through the entire src/fcpat.c file, wherever ->size is used (because that is the "allocated" size of the elts array, it is never reduced or zeroed out.  In other words, fontconfig-2.14.2 is not designed to actually release the memory allocated here back to the OS at all.

So, this is a bug, or rather design deficiency, in FontConfig that requires a refactoring, in my opinion.
 
The following users thanked this post: Ed.Kloonk


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf