Skip to content

Commit 72d7c80

Browse files
committed
Disallow weak pointers to stack (#274)
1 parent 5343c83 commit 72d7c80

File tree

3 files changed

+34
-26
lines changed

3 files changed

+34
-26
lines changed

playground/umka.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/umka_vm.c

+31-25
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ static FORCE_INLINE void stackChangeFrameRefCnt(Fiber *fiber, HeapPages *pages,
337337
}
338338

339339

340-
static FORCE_INLINE void *chunkAlloc(HeapPages *pages, int64_t size, Type *type, ExternFunc onFree, Error *error)
340+
static FORCE_INLINE void *chunkAlloc(HeapPages *pages, int64_t size, Type *type, ExternFunc onFree, bool isStack, Error *error)
341341
{
342342
// Page layout: header, data, footer (char), padding, header, data, footer (char), padding...
343343
int64_t chunkSize = align(sizeof(HeapChunkHeader) + align(size + 1, sizeof(int64_t)), VM_MIN_HEAP_CHUNK);
@@ -365,6 +365,7 @@ static FORCE_INLINE void *chunkAlloc(HeapPages *pages, int64_t size, Type *type,
365365
chunk->type = type;
366366
chunk->onFree = onFree;
367367
chunk->ip = pages->fiber->ip;
368+
chunk->isStack = isStack;
368369

369370
page->numOccupiedChunks++;
370371
page->refCnt++;
@@ -538,7 +539,7 @@ void vmInit(VM *vm, int stackSize, bool fileSystemEnabled, Error *error)
538539

539540
pageInit(&vm->pages, vm->fiber, &vm->strLenCache, error);
540541

541-
vm->fiber->stack = chunkAlloc(&vm->pages, stackSize * sizeof(Slot), NULL, NULL, error);
542+
vm->fiber->stack = chunkAlloc(&vm->pages, stackSize * sizeof(Slot), NULL, NULL, true, error);
542543
vm->fiber->stackSize = stackSize;
543544

544545
candidateInit(&vm->refCntChangeCandidates);
@@ -910,7 +911,7 @@ static FORCE_INLINE void doAllocDynArray(HeapPages *pages, DynArray *array, Type
910911

911912
DynArrayDimensions dims = {.len = len, .capacity = 2 * (len + 1)};
912913

913-
char *dimsAndData = chunkAlloc(pages, sizeof(DynArrayDimensions) + dims.capacity * array->itemSize, array->type, NULL, error);
914+
char *dimsAndData = chunkAlloc(pages, sizeof(DynArrayDimensions) + dims.capacity * array->itemSize, array->type, NULL, false, error);
914915
*(DynArrayDimensions *)dimsAndData = dims;
915916

916917
array->data = dimsAndData + sizeof(DynArrayDimensions);
@@ -930,7 +931,7 @@ static FORCE_INLINE void doGetEmptyDynArray(DynArray *array, Type *type)
930931
static FORCE_INLINE void doAllocMap(HeapPages *pages, Map *map, Type *type, Error *error)
931932
{
932933
map->type = type;
933-
map->root = chunkAlloc(pages, typeSizeNoCheck(type->base), type->base, NULL, error);
934+
map->root = chunkAlloc(pages, typeSizeNoCheck(type->base), type->base, NULL, false, error);
934935
map->root->len = 0;
935936
}
936937

@@ -1013,7 +1014,7 @@ static FORCE_INLINE MapNode *doGetMapNode(Map *map, Slot key, bool createMissing
10131014
return NULL;
10141015

10151016
Type *nodeType = map->type->base;
1016-
*child = (MapNode *)chunkAlloc(pages, typeSizeNoCheck(nodeType), nodeType, NULL, error);
1017+
*child = (MapNode *)chunkAlloc(pages, typeSizeNoCheck(nodeType), nodeType, NULL, false, error);
10171018
}
10181019

10191020
if (nodePtrInParent)
@@ -1032,7 +1033,7 @@ static MapNode *doCopyMapNode(Map *map, MapNode *node, Fiber *fiber, HeapPages *
10321033
return NULL;
10331034

10341035
Type *nodeType = map->type->base;
1035-
MapNode *result = (MapNode *)chunkAlloc(pages, typeSizeNoCheck(nodeType), nodeType, NULL, error);
1036+
MapNode *result = (MapNode *)chunkAlloc(pages, typeSizeNoCheck(nodeType), nodeType, NULL, false, error);
10361037

10371038
result->len = node->len;
10381039

@@ -1045,7 +1046,7 @@ static MapNode *doCopyMapNode(Map *map, MapNode *node, Fiber *fiber, HeapPages *
10451046
doBasicDeref(&srcKey, keyType->kind, error);
10461047

10471048
// When allocating dynamic arrays, we mark with type the data chunk, not the header chunk
1048-
result->key = chunkAlloc(pages, typeSizeNoCheck(keyType), keyType->kind == TYPE_DYNARRAY ? NULL : keyType, NULL, error);
1049+
result->key = chunkAlloc(pages, typeSizeNoCheck(keyType), keyType->kind == TYPE_DYNARRAY ? NULL : keyType, NULL, false, error);
10491050

10501051
if (typeGarbageCollected(keyType))
10511052
doBasicChangeRefCnt(fiber, pages, srcKey.ptrVal, keyType, TOK_PLUSPLUS);
@@ -1062,7 +1063,7 @@ static MapNode *doCopyMapNode(Map *map, MapNode *node, Fiber *fiber, HeapPages *
10621063
doBasicDeref(&srcItem, itemType->kind, error);
10631064

10641065
// When allocating dynamic arrays, we mark with type the data chunk, not the header chunk
1065-
result->data = chunkAlloc(pages, typeSizeNoCheck(itemType), itemType->kind == TYPE_DYNARRAY ? NULL : itemType, NULL, error);
1066+
result->data = chunkAlloc(pages, typeSizeNoCheck(itemType), itemType->kind == TYPE_DYNARRAY ? NULL : itemType, NULL, false, error);
10661067

10671068
if (typeGarbageCollected(itemType))
10681069
doBasicChangeRefCnt(fiber, pages, srcItem.ptrVal, itemType, TOK_PLUSPLUS);
@@ -1473,7 +1474,7 @@ static FORCE_INLINE void doBuiltinPrintf(Fiber *fiber, HeapPages *pages, bool co
14731474

14741475
if (needRealloc)
14751476
{
1476-
char *newStream = chunkAlloc(pages, 2 * (prevLen + len) + 1, NULL, NULL, error);
1477+
char *newStream = chunkAlloc(pages, 2 * (prevLen + len) + 1, NULL, NULL, false, error);
14771478
if (stream)
14781479
memcpy(newStream, stream, prevLen);
14791480
newStream[prevLen] = 0;
@@ -1550,7 +1551,7 @@ static FORCE_INLINE void doBuiltinScanf(Fiber *fiber, HeapPages *pages, bool con
15501551
doBasicChangeRefCnt(fiber, pages, *dest, &destType, TOK_MINUSMINUS);
15511552

15521553
// Allocate new string
1553-
*dest = chunkAlloc(pages, strlen(src) + 1, NULL, NULL, error);
1554+
*dest = chunkAlloc(pages, strlen(src) + 1, NULL, NULL, false, error);
15541555
strcpy(*dest, src);
15551556
free(src);
15561557

@@ -1580,7 +1581,7 @@ static FORCE_INLINE void doBuiltinNew(Fiber *fiber, HeapPages *pages, Error *err
15801581
if (type && type->kind == TYPE_DYNARRAY)
15811582
type = NULL;
15821583

1583-
void *result = chunkAlloc(pages, size, type, NULL, error);
1584+
void *result = chunkAlloc(pages, size, type, NULL, false, error);
15841585

15851586
(--fiber->top)->ptrVal = result;
15861587
}
@@ -1676,7 +1677,7 @@ static FORCE_INLINE void doBuiltinMaketostr(Fiber *fiber, HeapPages *pages, Erro
16761677

16771678
if (src->data)
16781679
{
1679-
dest = chunkAlloc(pages, getDims(src)->len + 1, NULL, NULL, error);
1680+
dest = chunkAlloc(pages, getDims(src)->len + 1, NULL, NULL, false, error);
16801681
memcpy(dest, src->data, getDims(src)->len);
16811682
dest[getDims(src)->len] = 0;
16821683
}
@@ -1984,7 +1985,7 @@ static FORCE_INLINE void doBuiltinSlice(Fiber *fiber, HeapPages *pages, Error *e
19841985
else
19851986
{
19861987
// String
1987-
char *substr = chunkAlloc(pages, endIndex - startIndex + 1, NULL, NULL, error);
1988+
char *substr = chunkAlloc(pages, endIndex - startIndex + 1, NULL, NULL, false, error);
19881989
memcpy(substr, &str[startIndex], endIndex - startIndex);
19891990
substr[endIndex - startIndex] = 0;
19901991

@@ -2174,10 +2175,10 @@ static FORCE_INLINE void doBuiltinFiberspawn(Fiber *fiber, HeapPages *pages, Err
21742175
int childEntryOffset = (fiber->top++)->intVal;
21752176

21762177
// Copy whole fiber context
2177-
Fiber *child = chunkAlloc(pages, sizeof(Fiber), NULL, NULL, error);
2178+
Fiber *child = chunkAlloc(pages, sizeof(Fiber), NULL, NULL, false, error);
21782179

21792180
*child = *fiber;
2180-
child->stack = chunkAlloc(pages, child->stackSize * sizeof(Slot), NULL, NULL, error);
2181+
child->stack = chunkAlloc(pages, child->stackSize * sizeof(Slot), NULL, NULL, true, error);
21812182
child->top = child->base = child->stack + child->stackSize - 1;
21822183

21832184
// Call child fiber function
@@ -2220,7 +2221,7 @@ static FORCE_INLINE void doBuiltinRepr(Fiber *fiber, HeapPages *pages, Error *er
22202221
enum {MAX_REPR_DEPTH = 20};
22212222

22222223
int len = doFillReprBuf(val, type, NULL, 0, MAX_REPR_DEPTH, fiber->strLenCache, error); // Predict buffer length
2223-
char *buf = chunkAlloc(pages, len + 1, NULL, NULL, error); // Allocate buffer
2224+
char *buf = chunkAlloc(pages, len + 1, NULL, NULL, false, error); // Allocate buffer
22242225
doFillReprBuf(val, type, buf, INT_MAX, MAX_REPR_DEPTH, fiber->strLenCache, error); // Fill buffer
22252226

22262227
fiber->top->ptrVal = buf;
@@ -2488,7 +2489,7 @@ static FORCE_INLINE void doBinary(Fiber *fiber, HeapPages *pages, Error *error)
24882489
}
24892490
else
24902491
{
2491-
buf = chunkAlloc(pages, 2 * (lhsLen + rhsLen) + 1, NULL, NULL, error);
2492+
buf = chunkAlloc(pages, 2 * (lhsLen + rhsLen) + 1, NULL, NULL, false, error);
24922493
memmove(buf, lhsStr, lhsLen);
24932494
}
24942495

@@ -2707,8 +2708,8 @@ static FORCE_INLINE void doGetMapPtr(Fiber *fiber, HeapPages *pages, Error *erro
27072708
if (!node->data)
27082709
{
27092710
// When allocating dynamic arrays, we mark with type the data chunk, not the header chunk
2710-
node->key = chunkAlloc(pages, typeSizeNoCheck(keyType), keyType->kind == TYPE_DYNARRAY ? NULL : keyType, NULL, error);
2711-
node->data = chunkAlloc(pages, typeSizeNoCheck(itemType), itemType->kind == TYPE_DYNARRAY ? NULL : itemType, NULL, error);
2711+
node->key = chunkAlloc(pages, typeSizeNoCheck(keyType), keyType->kind == TYPE_DYNARRAY ? NULL : keyType, NULL, false, error);
2712+
node->data = chunkAlloc(pages, typeSizeNoCheck(itemType), itemType->kind == TYPE_DYNARRAY ? NULL : itemType, NULL, false, error);
27122713

27132714
// Increase key ref count
27142715
if (typeGarbageCollected(keyType))
@@ -2772,11 +2773,15 @@ static FORCE_INLINE void doWeakenPtr(Fiber *fiber, HeapPages *pages)
27722773
uint64_t weakPtr = 0;
27732774

27742775
HeapPage *page = pageFind(pages, ptr, false);
2775-
if (page && pageGetChunkHeader(page, ptr)->refCnt > 0)
2776+
if (page)
27762777
{
2777-
int pageId = page->id;
2778-
int pageOffset = (char *)ptr - (char *)page->ptr;
2779-
weakPtr = ((uint64_t)pageId << 32) | pageOffset;
2778+
HeapChunkHeader *chunk = pageGetChunkHeader(page, ptr);
2779+
if (chunk->refCnt > 0 && !chunk->isStack)
2780+
{
2781+
int pageId = page->id;
2782+
int pageOffset = (char *)ptr - (char *)page->ptr;
2783+
weakPtr = ((uint64_t)pageId << 32) | pageOffset;
2784+
}
27802785
}
27812786

27822787
fiber->top->weakPtrVal = weakPtr;
@@ -2796,7 +2801,8 @@ static FORCE_INLINE void doStrengthenPtr(Fiber *fiber, HeapPages *pages)
27962801
int pageOffset = weakPtr & 0x7FFFFFFF;
27972802
ptr = (char *)page->ptr + pageOffset;
27982803

2799-
if (pageGetChunkHeader(page, ptr)->refCnt == 0)
2804+
HeapChunkHeader * chunk = pageGetChunkHeader(page, ptr);
2805+
if (chunk->refCnt == 0 || chunk->isStack)
28002806
ptr = NULL;
28012807
}
28022808

@@ -3224,7 +3230,7 @@ void vmSetHook(VM *vm, HookEvent event, HookFunc hook)
32243230

32253231
void *vmAllocData(VM *vm, int size, ExternFunc onFree)
32263232
{
3227-
return chunkAlloc(&vm->pages, size, NULL, onFree, vm->error);
3233+
return chunkAlloc(&vm->pages, size, NULL, onFree, false, vm->error);
32283234
}
32293235

32303236

src/umka_vm.h

+2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ typedef struct
197197
struct tagType *type; // Optional type for garbage collection
198198
ExternFunc onFree; // Optional callback called when ref count reaches zero
199199
int64_t ip; // Optional instruction pointer at which the chunk has been allocated
200+
bool isStack;
201+
bool reserved[7];
200202
} HeapChunkHeader;
201203

202204

0 commit comments

Comments
 (0)