charmap: Store hashmap nodes in charmap stack

This helps update all the pointers during reallocation.
This commit is contained in:
Jakub Kądziołka
2021-04-16 13:58:27 +02:00
committed by Eldred Habert
parent 8885f7bcf6
commit 215e26b478
4 changed files with 34 additions and 24 deletions

View File

@@ -44,10 +44,14 @@ struct Charmap {
static HashMap charmaps; static HashMap charmaps;
static struct Charmap *currentCharmap; /*
* Store pointers to hashmap nodes, so that there is only one pointer to the memory block
* that gets reallocated.
*/
static struct Charmap **currentCharmap;
struct CharmapStackEntry { struct CharmapStackEntry {
struct Charmap *charmap; struct Charmap **charmap;
struct CharmapStackEntry *next; struct CharmapStackEntry *next;
}; };
@@ -58,15 +62,14 @@ static struct Charmap *charmap_Get(const char *name)
return hash_GetElement(charmaps, name); return hash_GetElement(charmaps, name);
} }
static struct Charmap *resizeCharmap(struct Charmap *map, size_t capacity) static void resizeCharmap(struct Charmap **map, size_t capacity)
{ {
struct Charmap *new = realloc(map, sizeof(*map) + sizeof(*map->nodes) * capacity); *map = realloc(*map, sizeof(**map) + sizeof(*(*map)->nodes) * capacity);
if (!new) if (!*map)
fatalerror("Failed to %s charmap: %s\n", fatalerror("Failed to %s charmap: %s\n",
map ? "create" : "resize", strerror(errno)); *map ? "create" : "resize", strerror(errno));
new->capacity = capacity; (**map).capacity = capacity;
return new;
} }
static void initNode(struct Charnode *node) static void initNode(struct Charnode *node)
@@ -95,19 +98,18 @@ struct Charmap *charmap_New(const char *name, const char *baseName)
/* Init the new charmap's fields */ /* Init the new charmap's fields */
if (base) { if (base) {
charmap = resizeCharmap(NULL, base->capacity); resizeCharmap(&charmap, base->capacity);
charmap->usedNodes = base->usedNodes; charmap->usedNodes = base->usedNodes;
memcpy(charmap->nodes, base->nodes, sizeof(base->nodes[0]) * charmap->usedNodes); memcpy(charmap->nodes, base->nodes, sizeof(base->nodes[0]) * charmap->usedNodes);
} else { } else {
charmap = resizeCharmap(NULL, INITIAL_CAPACITY); resizeCharmap(&charmap, INITIAL_CAPACITY);
charmap->usedNodes = 1; charmap->usedNodes = 1;
initNode(&charmap->nodes[0]); /* Init the root node */ initNode(&charmap->nodes[0]); /* Init the root node */
} }
charmap->name = strdup(name); charmap->name = strdup(name);
hash_AddElement(charmaps, charmap->name, charmap); currentCharmap = (struct Charmap **)hash_AddElement(charmaps, charmap->name, charmap);
currentCharmap = charmap;
return charmap; return charmap;
} }
@@ -120,7 +122,7 @@ void charmap_Delete(struct Charmap *charmap)
void charmap_Set(const char *name) void charmap_Set(const char *name)
{ {
struct Charmap *charmap = charmap_Get(name); struct Charmap **charmap = (struct Charmap **)hash_GetNode(charmaps, name);
if (charmap == NULL) if (charmap == NULL)
error("Charmap '%s' doesn't exist\n", name); error("Charmap '%s' doesn't exist\n", name);
@@ -158,25 +160,26 @@ void charmap_Pop(void)
void charmap_Add(char *mapping, uint8_t value) void charmap_Add(char *mapping, uint8_t value)
{ {
struct Charnode *node = &currentCharmap->nodes[0]; struct Charmap *charmap = *currentCharmap;
struct Charnode *node = &charmap->nodes[0];
for (uint8_t c; *mapping; mapping++) { for (uint8_t c; *mapping; mapping++) {
c = *mapping - 1; c = *mapping - 1;
if (node->next[c]) { if (node->next[c]) {
node = &currentCharmap->nodes[node->next[c]]; node = &charmap->nodes[node->next[c]];
} else { } else {
/* Register next available node */ /* Register next available node */
node->next[c] = currentCharmap->usedNodes; node->next[c] = charmap->usedNodes;
/* If no more nodes are available, get new ones */ /* If no more nodes are available, get new ones */
if (currentCharmap->usedNodes == currentCharmap->capacity) { if (charmap->usedNodes == charmap->capacity) {
currentCharmap->capacity *= 2; charmap->capacity *= 2;
currentCharmap = resizeCharmap(currentCharmap, currentCharmap->capacity); resizeCharmap(currentCharmap, charmap->capacity);
hash_ReplaceElement(charmaps, currentCharmap->name, currentCharmap); charmap = *currentCharmap;
} }
/* Switch to and init new node */ /* Switch to and init new node */
node = &currentCharmap->nodes[currentCharmap->usedNodes++]; node = &charmap->nodes[charmap->usedNodes++];
initNode(node); initNode(node);
} }
} }
@@ -197,7 +200,8 @@ size_t charmap_Convert(char const *input, uint8_t *output)
* If no match, read a UTF-8 codepoint and output that. * If no match, read a UTF-8 codepoint and output that.
*/ */
size_t outputLen = 0; size_t outputLen = 0;
struct Charnode const *node = &currentCharmap->nodes[0]; struct Charmap const *charmap = *currentCharmap;
struct Charnode const *node = &charmap->nodes[0];
struct Charnode const *match = NULL; struct Charnode const *match = NULL;
size_t rewindDistance = 0; size_t rewindDistance = 0;
@@ -209,7 +213,7 @@ size_t charmap_Convert(char const *input, uint8_t *output)
input++; /* Consume that char */ input++; /* Consume that char */
rewindDistance++; rewindDistance++;
node = &currentCharmap->nodes[node->next[c]]; node = &charmap->nodes[node->next[c]];
if (node->isTerminal) { if (node->isTerminal) {
match = node; match = node;
rewindDistance = 0; /* Rewind from after the match */ rewindDistance = 0; /* Rewind from after the match */
@@ -218,7 +222,7 @@ size_t charmap_Convert(char const *input, uint8_t *output)
} else { } else {
input -= rewindDistance; /* Rewind */ input -= rewindDistance; /* Rewind */
rewindDistance = 0; rewindDistance = 0;
node = &currentCharmap->nodes[0]; node = &charmap->nodes[0];
if (match) { /* Arrived at a dead end with a match found */ if (match) { /* Arrived at a dead end with a match found */
*output++ = match->value; *output++ = match->value;

View File

@@ -0,0 +1,6 @@
; Triggering a charmap realloc while the charmap has been pushed onto the stack used
; to induce a use-after-free.
pushc
charmap "000000000000000000000000000000000",12
popc
charmap "000000000000000000000000000000000",34

View File

View File