Bug 17832 - Memory leaks due to FcStrStaticName use for external patterns

Use the reference-counted strings instead of the static strings

Patch from Karl Tomlinson
This commit is contained in:
Akira TAGOH 2012-03-28 13:37:15 +09:00
parent ea1c6ea337
commit d8dcff7b96
7 changed files with 54 additions and 77 deletions

View File

@ -1009,7 +1009,7 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
case FcOpPlus: case FcOpPlus:
v.type = FcTypeString; v.type = FcTypeString;
str = FcStrPlus (vl.u.s, vr.u.s); str = FcStrPlus (vl.u.s, vr.u.s);
v.u.s = FcStrStaticName (str); v.u.s = FcSharedStr (str);
FcStrFree (str); FcStrFree (str);
if (!v.u.s) if (!v.u.s)

View File

@ -139,7 +139,7 @@ FcFini (void)
if (_fcConfig) if (_fcConfig)
FcConfigDestroy (_fcConfig); FcConfigDestroy (_fcConfig);
FcPatternFini (); FcObjectFini ();
FcCacheFini (); FcCacheFini ();
if (FcDebug() & FC_DBG_MEMORY) if (FcDebug() & FC_DBG_MEMORY)
FcMemReport (); FcMemReport ();
@ -221,7 +221,7 @@ static struct {
{ "vstack" }, { "vstack" },
{ "attr" }, { "attr" },
{ "pstack" }, { "pstack" },
{ "staticstr" }, { "sharedstr" },
}; };
static int FcAllocCount, FcAllocMem; static int FcAllocCount, FcAllocMem;

View File

@ -103,7 +103,7 @@
#define FC_MEM_VSTACK 26 #define FC_MEM_VSTACK 26
#define FC_MEM_ATTR 27 #define FC_MEM_ATTR 27
#define FC_MEM_PSTACK 28 #define FC_MEM_PSTACK 28
#define FC_MEM_STATICSTR 29 #define FC_MEM_SHAREDSTR 29
#define FC_MEM_NUM 30 #define FC_MEM_NUM 30
@ -948,14 +948,14 @@ FcPatternObjectGetBool (const FcPattern *p, FcObject object, int n, FcBool *b);
FcPrivate FcResult FcPrivate FcResult
FcPatternObjectGetLangSet (const FcPattern *p, FcObject object, int n, FcLangSet **ls); FcPatternObjectGetLangSet (const FcPattern *p, FcObject object, int n, FcLangSet **ls);
FcPrivate void
FcPatternFini (void);
FcPrivate FcBool FcPrivate FcBool
FcPatternAppend (FcPattern *p, FcPattern *s); FcPatternAppend (FcPattern *p, FcPattern *s);
FcPrivate const FcChar8 * FcPrivate const FcChar8 *
FcStrStaticName (const FcChar8 *name); FcSharedStr (const FcChar8 *name);
FcPrivate FcBool
FcSharedStrFree (const FcChar8 *name);
FcPrivate FcChar32 FcPrivate FcChar32
FcStringHash (const FcChar8 *s); FcStringHash (const FcChar8 *s);

View File

@ -67,13 +67,16 @@ FcObjectSetAdd (FcObjectSet *os, const char *object)
low = 0; low = 0;
mid = 0; mid = 0;
c = 1; c = 1;
object = (char *)FcStrStaticName ((FcChar8 *)object); object = (char *)FcSharedStr ((FcChar8 *)object);
while (low <= high) while (low <= high)
{ {
mid = (low + high) >> 1; mid = (low + high) >> 1;
c = os->objects[mid] - object; c = os->objects[mid] - object;
if (c == 0) if (c == 0)
{
FcSharedStrFree ((FcChar8 *)object);
return FcTrue; return FcTrue;
}
if (c < 0) if (c < 0)
low = mid + 1; low = mid + 1;
else else
@ -91,8 +94,13 @@ FcObjectSetAdd (FcObjectSet *os, const char *object)
void void
FcObjectSetDestroy (FcObjectSet *os) FcObjectSetDestroy (FcObjectSet *os)
{ {
int i;
if (os->objects) if (os->objects)
{ {
for (i = 0; i < os->nobject; i++)
FcSharedStrFree ((FcChar8 *)os->objects[i]);
FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *)); FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
free ((void *) os->objects); free ((void *) os->objects);
} }

View File

@ -572,9 +572,10 @@ FcNameBool (const FcChar8 *v, FcBool *result)
} }
static FcValue static FcValue
FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m) FcNameConvert (FcType type, FcChar8 *string)
{ {
FcValue v; FcValue v;
FcMatrix m;
v.type = type; v.type = type;
switch (v.type) { switch (v.type) {
@ -583,7 +584,7 @@ FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
v.u.i = atoi ((char *) string); v.u.i = atoi ((char *) string);
break; break;
case FcTypeString: case FcTypeString:
v.u.s = FcStrStaticName(string); v.u.s = FcSharedStr (string);
if (!v.u.s) if (!v.u.s)
v.type = FcTypeVoid; v.type = FcTypeVoid;
break; break;
@ -595,8 +596,8 @@ FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
v.u.d = strtod ((char *) string, 0); v.u.d = strtod ((char *) string, 0);
break; break;
case FcTypeMatrix: case FcTypeMatrix:
v.u.m = m; sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy); v.u.m = FcMatrixCopy (&m);
break; break;
case FcTypeCharSet: case FcTypeCharSet:
v.u.c = FcNameParseCharSet (string); v.u.c = FcNameParseCharSet (string);
@ -648,7 +649,6 @@ FcNameParse (const FcChar8 *name)
FcChar8 *e; FcChar8 *e;
FcChar8 delim; FcChar8 delim;
FcValue v; FcValue v;
FcMatrix m;
const FcObjectType *t; const FcObjectType *t;
const FcConstant *c; const FcConstant *c;
@ -699,31 +699,13 @@ FcNameParse (const FcChar8 *name)
name = FcNameFindNext (name, ":,", save, &delim); name = FcNameFindNext (name, ":,", save, &delim);
if (t) if (t)
{ {
v = FcNameConvert (t->type, save, &m); v = FcNameConvert (t->type, save);
if (!FcPatternAdd (pat, t->object, v, FcTrue)) if (!FcPatternAdd (pat, t->object, v, FcTrue))
{ {
switch (v.type) { FcValueDestroy (v);
case FcTypeCharSet:
FcCharSetDestroy ((FcCharSet *) v.u.c);
break;
case FcTypeLangSet:
FcLangSetDestroy ((FcLangSet *) v.u.l);
break;
default:
break;
}
goto bail2; goto bail2;
} }
switch (v.type) { FcValueDestroy (v);
case FcTypeCharSet:
FcCharSetDestroy ((FcCharSet *) v.u.c);
break;
case FcTypeLangSet:
FcLangSetDestroy ((FcLangSet *) v.u.l);
break;
default:
break;
}
} }
if (delim != ',') if (delim != ',')
break; break;

View File

@ -26,9 +26,6 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
static FcBool
FcHashOwnsName(const FcChar8 *name);
FcPattern * FcPattern *
FcPatternCreate (void) FcPatternCreate (void)
{ {
@ -50,7 +47,7 @@ FcValueDestroy (FcValue v)
{ {
switch (v.type) { switch (v.type) {
case FcTypeString: case FcTypeString:
if (!FcHashOwnsName(v.u.s)) if (!FcSharedStrFree (v.u.s))
FcStrFree ((FcChar8 *) v.u.s); FcStrFree ((FcChar8 *) v.u.s);
break; break;
case FcTypeMatrix: case FcTypeMatrix:
@ -98,7 +95,7 @@ FcValueSave (FcValue v)
{ {
switch (v.type) { switch (v.type) {
case FcTypeString: case FcTypeString:
v.u.s = FcStrStaticName (v.u.s); v.u.s = FcSharedStr (v.u.s);
if (!v.u.s) if (!v.u.s)
v.type = FcTypeVoid; v.type = FcTypeVoid;
break; break;
@ -131,7 +128,7 @@ FcValueListDestroy (FcValueListPtr l)
{ {
switch (l->value.type) { switch (l->value.type) {
case FcTypeString: case FcTypeString:
if (!FcHashOwnsName((FcChar8 *)l->value.u.s)) if (!FcSharedStrFree ((FcChar8 *)l->value.u.s))
FcStrFree ((FcChar8 *)l->value.u.s); FcStrFree ((FcChar8 *)l->value.u.s);
break; break;
case FcTypeMatrix: case FcTypeMatrix:
@ -652,7 +649,7 @@ FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
} }
v.type = FcTypeString; v.type = FcTypeString;
v.u.s = FcStrStaticName(s); v.u.s = s;
return FcPatternObjectAdd (p, object, v, FcTrue); return FcPatternObjectAdd (p, object, v, FcTrue);
} }
@ -1030,23 +1027,35 @@ bail0:
static struct objectBucket { static struct objectBucket {
struct objectBucket *next; struct objectBucket *next;
FcChar32 hash; FcChar32 hash;
int ref_count;
} *FcObjectBuckets[OBJECT_HASH_SIZE]; } *FcObjectBuckets[OBJECT_HASH_SIZE];
static FcBool FcBool
FcHashOwnsName (const FcChar8 *name) FcSharedStrFree (const FcChar8 *name)
{ {
FcChar32 hash = FcStringHash (name); FcChar32 hash = FcStringHash (name);
struct objectBucket **p; struct objectBucket **p;
struct objectBucket *b; struct objectBucket *b;
int size;
for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
if (b->hash == hash && ((char *)name == (char *) (b + 1))) if (b->hash == hash && ((char *)name == (char *) (b + 1)))
{
b->ref_count--;
if (!b->ref_count)
{
*p = b->next;
size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
FcMemFree (FC_MEM_SHAREDSTR, size + sizeof (int));
free (b);
}
return FcTrue; return FcTrue;
}
return FcFalse; return FcFalse;
} }
const FcChar8 * const FcChar8 *
FcStrStaticName (const FcChar8 *name) FcSharedStr (const FcChar8 *name)
{ {
FcChar32 hash = FcStringHash (name); FcChar32 hash = FcStringHash (name);
struct objectBucket **p; struct objectBucket **p;
@ -1055,7 +1064,10 @@ FcStrStaticName (const FcChar8 *name)
for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1))) if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
{
b->ref_count++;
return (FcChar8 *) (b + 1); return (FcChar8 *) (b + 1);
}
size = sizeof (struct objectBucket) + strlen ((char *)name) + 1; size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
/* /*
* workaround valgrind warning because glibc takes advantage of how it knows memory is * workaround valgrind warning because glibc takes advantage of how it knows memory is
@ -1063,44 +1075,17 @@ FcStrStaticName (const FcChar8 *name)
*/ */
size = (size + 3) & ~3; size = (size + 3) & ~3;
b = malloc (size); b = malloc (size);
FcMemAlloc (FC_MEM_STATICSTR, size); FcMemAlloc (FC_MEM_SHAREDSTR, size);
if (!b) if (!b)
return NULL; return NULL;
b->next = 0; b->next = 0;
b->hash = hash; b->hash = hash;
b->ref_count = 1;
strcpy ((char *) (b + 1), (char *)name); strcpy ((char *) (b + 1), (char *)name);
*p = b; *p = b;
return (FcChar8 *) (b + 1); return (FcChar8 *) (b + 1);
} }
static void
FcStrStaticNameFini (void)
{
int i, size;
struct objectBucket *b, *next;
char *name;
for (i = 0; i < OBJECT_HASH_SIZE; i++)
{
for (b = FcObjectBuckets[i]; b; b = next)
{
next = b->next;
name = (char *) (b + 1);
size = sizeof (struct objectBucket) + strlen (name) + 1;
FcMemFree (FC_MEM_STATICSTR, size + sizeof (int));
free (b);
}
FcObjectBuckets[i] = 0;
}
}
void
FcPatternFini (void)
{
FcStrStaticNameFini ();
FcObjectFini ();
}
FcBool FcBool
FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat) FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
{ {

View File

@ -104,7 +104,7 @@ FcExprCreateString (FcConfig *config, const FcChar8 *s)
if (e) if (e)
{ {
e->op = FcOpString; e->op = FcOpString;
e->u.sval = FcStrStaticName (s); e->u.sval = FcSharedStr (s);
} }
return e; return e;
} }
@ -176,7 +176,7 @@ FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
if (e) if (e)
{ {
e->op = FcOpConst; e->op = FcOpConst;
e->u.constant = FcStrStaticName (constant); e->u.constant = FcSharedStr (constant);
} }
return e; return e;
} }
@ -205,6 +205,7 @@ FcExprDestroy (FcExpr *e)
case FcOpDouble: case FcOpDouble:
break; break;
case FcOpString: case FcOpString:
FcSharedStrFree (e->u.sval);
break; break;
case FcOpMatrix: case FcOpMatrix:
FcMatrixFree (e->u.mval); FcMatrixFree (e->u.mval);
@ -222,6 +223,7 @@ FcExprDestroy (FcExpr *e)
case FcOpField: case FcOpField:
break; break;
case FcOpConst: case FcOpConst:
FcSharedStrFree (e->u.constant);
break; break;
case FcOpAssign: case FcOpAssign:
case FcOpAssignReplace: case FcOpAssignReplace:
@ -2134,7 +2136,7 @@ FcPopValue (FcConfigParse *parse)
switch (vstack->tag) { switch (vstack->tag) {
case FcVStackString: case FcVStackString:
value.u.s = FcStrStaticName (vstack->u.string); value.u.s = FcSharedStr (vstack->u.string);
if (value.u.s) if (value.u.s)
value.type = FcTypeString; value.type = FcTypeString;
break; break;