mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
ffi: Make HLL calls safe against heap reallocation
In hll_call(), pointers to heap data passed by reference could become invalid if the heap was reallocated during the call. The previous implementation attempted to prevent this by calling heap_guarantee() to pre-allocate heap space. However, this approach does not work for certain functions in PastelChime2 HLL, which can perform an unbounded number of heap allocations. This commit removes heap_guarantee() and replaces it with a more robust copy-in/copy-out strategy: - Before the call (Copy-in): For reference arguments, the pointer value is copied from the heap to a local variable on the stack. A pointer to this local variable is then passed to the HLL function. - After the call (Copy-out): The pointer value, which may have been modified by the HLL function, is written back from the local variable to its original slot in the heap.
This commit is contained in:
@@ -78,15 +78,6 @@ int32_t heap_alloc_string(struct string *s);
|
||||
|
||||
void heap_describe_slot(int slot);
|
||||
|
||||
/*
|
||||
* Guarantee `headroom` free slots are available on the heap.
|
||||
*
|
||||
* XXX: this is a hack to fix an issue with HLL calls where a pointer into the
|
||||
* heap can be made invalid by a heap reallocation triggered within the
|
||||
* body of the HLL function.
|
||||
*/
|
||||
void heap_guarantee(unsigned headroom);
|
||||
|
||||
#ifdef VM_PRIVATE
|
||||
|
||||
extern uint32_t heap_next_seq;
|
||||
|
||||
@@ -303,13 +303,13 @@ void hll_call(int libno, int fno)
|
||||
if (!fun->fun)
|
||||
VM_ERROR("Unimplemented HLL function: %s.%s", ain->libraries[libno].name, f->name);
|
||||
|
||||
// XXX: Try to prevent the heap from being reallocated mid-call.
|
||||
// This only works to the extent that HLL functions can guarantee
|
||||
// no more than 64 heap allocations occur within the call...
|
||||
heap_guarantee(64);
|
||||
|
||||
void *args[HLL_MAX_ARGS];
|
||||
void *ptrs[HLL_MAX_ARGS];
|
||||
// Copy reference arguments to the stack to protect against heap
|
||||
// reallocation during HLL calls.
|
||||
void *heap_ptrs[HLL_MAX_ARGS];
|
||||
int heap_slots[HLL_MAX_ARGS];
|
||||
|
||||
for (int i = f->nr_arguments - 1; i >= 0; i--) {
|
||||
switch (f->arguments[i].type.data) {
|
||||
case AIN_REF_INT:
|
||||
@@ -330,7 +330,9 @@ void hll_call(int libno, int fno)
|
||||
break;
|
||||
case AIN_REF_STRING:
|
||||
stack_ptr--;
|
||||
ptrs[i] = &heap[stack[stack_ptr].i].s;
|
||||
heap_slots[i] = stack[stack_ptr].i;
|
||||
heap_ptrs[i] = heap[stack[stack_ptr].i].s;
|
||||
ptrs[i] = &heap_ptrs[i];
|
||||
args[i] = &ptrs[i];
|
||||
break;
|
||||
case AIN_STRUCT:
|
||||
@@ -341,7 +343,9 @@ void hll_call(int libno, int fno)
|
||||
case AIN_REF_STRUCT:
|
||||
case AIN_REF_ARRAY_TYPE:
|
||||
stack_ptr--;
|
||||
ptrs[i] = &heap[stack[stack_ptr].i].page;
|
||||
heap_slots[i] = stack[stack_ptr].i;
|
||||
heap_ptrs[i] = heap[stack[stack_ptr].i].page;
|
||||
ptrs[i] = &heap_ptrs[i];
|
||||
args[i] = &ptrs[i];
|
||||
break;
|
||||
default:
|
||||
@@ -370,9 +374,13 @@ void hll_call(int libno, int fno)
|
||||
j++;
|
||||
break;
|
||||
case AIN_REF_STRING:
|
||||
heap[heap_slots[i]].s = heap_ptrs[i];
|
||||
break;
|
||||
case AIN_REF_STRUCT:
|
||||
case AIN_REF_FUNC_TYPE:
|
||||
case AIN_REF_ARRAY_TYPE:
|
||||
heap[heap_slots[i]].page = heap_ptrs[i];
|
||||
break;
|
||||
case AIN_REF_FUNC_TYPE:
|
||||
break;
|
||||
case AIN_ARRAY_TYPE:
|
||||
// Sys41VM doesn't make a copy when passing an array by value.
|
||||
|
||||
-13
@@ -60,19 +60,6 @@ void heap_grow(size_t new_size)
|
||||
heap_size = new_size;
|
||||
}
|
||||
|
||||
void heap_guarantee(unsigned headroom)
|
||||
{
|
||||
if (heap_size - heap_free_ptr >= headroom)
|
||||
return;
|
||||
|
||||
size_t new_size = heap_size;
|
||||
while (new_size - heap_free_ptr < headroom) {
|
||||
new_size += HEAP_ALLOC_STEP;
|
||||
}
|
||||
|
||||
heap_grow(new_size);
|
||||
}
|
||||
|
||||
void heap_init(void)
|
||||
{
|
||||
if (!heap) {
|
||||
|
||||
Reference in New Issue
Block a user