mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
charmap: Store hashmap nodes in charmap stack
This helps update all the pointers during reallocation.
This commit is contained in:
committed by
Eldred Habert
parent
8885f7bcf6
commit
215e26b478
@@ -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 = ¤tCharmap->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 = ¤tCharmap->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 = ¤tCharmap->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 = ¤tCharmap->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 = ¤tCharmap->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 = ¤tCharmap->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;
|
||||||
|
|||||||
6
test/asm/pushc-without-switch.asm
Normal file
6
test/asm/pushc-without-switch.asm
Normal 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
|
||||||
0
test/asm/pushc-without-switch.err
Normal file
0
test/asm/pushc-without-switch.err
Normal file
0
test/asm/pushc-without-switch.out
Normal file
0
test/asm/pushc-without-switch.out
Normal file
Reference in New Issue
Block a user