Skip to content

Commit

Permalink
Fix an overflow bug in the text measurement cache (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicbarker authored Oct 15, 2024
1 parent 3b03a79 commit 3dffbea
Showing 1 changed file with 34 additions and 5 deletions.
39 changes: 34 additions & 5 deletions clay.h
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@ typedef struct
Clay_Dimensions dimensions;
uint32_t id;
int32_t nextIndex;
uint32_t generation;
} Clay__MeasureTextCacheItem;

Clay__MeasureTextCacheItem CLAY__MEASURE_TEXT_CACHE_ITEM_DEFAULT = CLAY__INIT(Clay__MeasureTextCacheItem) { };
Expand Down Expand Up @@ -1342,6 +1343,7 @@ Clay__LayoutElementTreeRootArray Clay__layoutElementTreeRoots;
Clay__LayoutElementHashMapItemArray Clay__layoutElementsHashMapInternal;
Clay__int32_tArray Clay__layoutElementsHashMap;
Clay__MeasureTextCacheItemArray Clay__measureTextHashMapInternal;
Clay__int32_tArray Clay__measureTextHashMapInternalFreeList;
Clay__int32_tArray Clay__measureTextHashMap;
Clay__int32_tArray Clay__openClipElementStack;
Clay__ElementIdArray Clay__pointerOverIds;
Expand Down Expand Up @@ -1451,17 +1453,43 @@ Clay_Dimensions Clay__MeasureTextCached(Clay_String *text, Clay_TextElementConfi
while (elementIndex != 0) {
Clay__MeasureTextCacheItem *hashEntry = Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, elementIndex);
if (hashEntry->id == id) {
hashEntry->generation = Clay__generation;
return hashEntry->dimensions;
}
elementIndexPrevious = elementIndex;
elementIndex = hashEntry->nextIndex;
// This element hasn't been seen in a few frames, delete the hash map item
if (Clay__generation - hashEntry->generation > 2) {
uint32_t nextIndex = hashEntry->nextIndex;
Clay__MeasureTextCacheItemArray_Set(&Clay__measureTextHashMapInternal, elementIndex, CLAY__INIT(Clay__MeasureTextCacheItem) {});
Clay__int32_tArray_Add(&Clay__measureTextHashMapInternalFreeList, elementIndex);
if (elementIndexPrevious == 0) {
Clay__measureTextHashMap.internalArray[hashBucket] = nextIndex;
} else {
Clay__MeasureTextCacheItem *previousHashEntry = Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, elementIndexPrevious);
previousHashEntry->nextIndex = nextIndex;
}
elementIndex = nextIndex;
} else {
elementIndexPrevious = elementIndex;
elementIndex = hashEntry->nextIndex;
}
}
Clay_Dimensions measured = Clay__MeasureText(text, config);
Clay__MeasureTextCacheItemArray_Add(&Clay__measureTextHashMapInternal, CLAY__INIT(Clay__MeasureTextCacheItem) { .dimensions = measured, .id = id });
uint32_t newItemIndex = 0;
if (Clay__measureTextHashMapInternalFreeList.length > 0) {
newItemIndex = Clay__int32_tArray_Get(&Clay__measureTextHashMapInternalFreeList, Clay__measureTextHashMapInternalFreeList.length - 1);
Clay__measureTextHashMapInternalFreeList.length--;
Clay__MeasureTextCacheItemArray_Set(&Clay__measureTextHashMapInternal, newItemIndex, CLAY__INIT(Clay__MeasureTextCacheItem) { .dimensions = measured, .id = id, .generation = Clay__generation });
} else {
if (Clay__measureTextHashMapInternal.length == Clay__measureTextHashMapInternal.capacity) {
return measured;
}
Clay__MeasureTextCacheItemArray_Add(&Clay__measureTextHashMapInternal, CLAY__INIT(Clay__MeasureTextCacheItem) { .dimensions = measured, .id = id, .generation = Clay__generation });
newItemIndex = Clay__measureTextHashMapInternal.length - 1;
}
if (elementIndexPrevious != 0) {
Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, elementIndexPrevious)->nextIndex = (int32_t)Clay__measureTextHashMapInternal.length - 1;
Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, elementIndexPrevious)->nextIndex = newItemIndex;
} else {
Clay__measureTextHashMap.internalArray[hashBucket] = (int32_t)Clay__measureTextHashMapInternal.length - 1;
Clay__measureTextHashMap.internalArray[hashBucket] = newItemIndex;
}
return measured;
}
Expand Down Expand Up @@ -1744,6 +1772,7 @@ void Clay__InitializePersistentMemory(Clay_Arena *arena) {
Clay__layoutElementsHashMapInternal = Clay__LayoutElementHashMapItemArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementsHashMap = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measureTextHashMapInternal = Clay__MeasureTextCacheItemArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measureTextHashMapInternalFreeList = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measureTextHashMap = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__pointerOverIds = Clay__ElementIdArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__debugElementData = Clay__DebugElementDataArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Expand Down

0 comments on commit 3dffbea

Please sign in to comment.