FcCharSetPutLeaf(): Fix missing move of new_leaves contents

If the `realloc(numbers)` call fails, shrinking the leaves allocation
back to the old size is not guaranteed to return the old pointer value.
While this might be the case with some malloc() implementations, realloc()
could also just mark the following area as free.
To make this less error-prone, we grow numbers first and then grow leaves
since the numbers content does not need to be relocated, but leaves does.

See https://bugs.freedesktop.org/show_bug.cgi?id=90867
This commit is contained in:
Alex Richardson 2021-07-20 09:30:57 +01:00
parent e1c7c6d744
commit 92ed966b74
1 changed files with 17 additions and 14 deletions

View File

@ -175,30 +175,33 @@ FcCharSetPutLeaf (FcCharSet *fcs,
}
else
{
int i;
unsigned int alloced = fcs->num;
intptr_t *new_leaves, distance;
intptr_t *new_leaves;
ptrdiff_t distance;
alloced *= 2;
new_leaves = realloc (leaves, alloced * sizeof (*leaves));
if (!new_leaves)
return FcFalse;
numbers = realloc (numbers, alloced * sizeof (*numbers));
if (!numbers)
return FcFalse;
new_leaves = realloc (leaves, alloced * sizeof (*leaves));
if (!new_leaves)
{
/* Revert the reallocation of leaves */
leaves = realloc (new_leaves, (alloced / 2) * sizeof (*new_leaves));
/*
* Revert the reallocation of numbers. We update numbers_offset
* first in case realloc() fails.
*/
fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
numbers = realloc (numbers, (alloced / 2) * sizeof (*numbers));
/* unlikely to fail though */
if (!leaves)
if (!numbers)
return FcFalse;
fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
return FcFalse;
}
distance = (intptr_t) new_leaves - (intptr_t) leaves;
if (new_leaves && distance)
{
int i;
for (i = 0; i < fcs->num; i++)
new_leaves[i] -= distance;
distance = (char *) new_leaves - (char *) leaves;
for (i = 0; i < fcs->num; i++) {
new_leaves[i] -= distance;
}
leaves = new_leaves;
}