#include "target_bridge.h" #include "target_host.h" #include #include #include #include extern void *factorio_target_original(void *); extern const uint8_t native_target_vtable[]; static _Alignas(16) uint8_t native_heap[65536]; static size_t native_cursor; static unsigned native_allocations; void *native_target_allocate(size_t size) { native_cursor=(native_cursor+15)&~(size_t)15; assert(size<=sizeof(native_heap)-native_cursor); void *result=native_heap+native_cursor; native_cursor+=size; ++native_allocations; return result; } void native_target_unsupported_delete(void *p) {(void)p;abort();} void native_target_unsupported_length(void *p) {(void)p;abort();} void native_target_unsupported_array_length(void *p) {(void)p;abort();} static uint64_t get(const uint8_t *data,size_t at) {uint64_t x;memcpy(&x,data+at,8);return x;} static void put(uint8_t *data,size_t at,uint64_t x) {memcpy(data+at,&x,8);} static uint64_t relocate(uint64_t pointer,uint64_t begin) { assert(pointer>=(uintptr_t)native_heap && pointer<=(uintptr_t)native_heap+sizeof(native_heap)); return pointer-(uintptr_t)native_heap+begin; } int main(void) { wasm_rt_init(); w2c_factorio__target module; struct w2c_target__host env={.module=&module}; wasm2c_factorio__target_instantiate(&module,&env); wasm_rt_memory_t *ram=w2c_factorio__target_memory(&module); assert(ram->size==1048576); uint8_t *memory=ram->data; for (unsigned iteration=0;iteration<512;++iteration) { uint64_t begin=131072+iteration*16,object=4096+(iteration%16)*256; memset(memory,0xa5,(size_t)ram->size); memset(native_heap,0xa5,sizeof(native_heap)); uint8_t original[144];memset(original,0xa5,sizeof(original)); native_cursor=0;native_allocations=0; assert(factorio_target_original(original)==original); assert(native_allocations==4 && native_cursor==2104); assert(factorio_guest_heap_init(&env.heap,memory,ram->size,begin,begin+65536)==0); uint64_t registers[32]={0}; for(unsigned i=19;i<30;++i) registers[i]=0x1234567800000000ull+iteration+i; registers[0]=object;registers[31]=ram->size-256; memcpy(memory,registers,sizeof(registers)); assert(w2c_factorio__target_run(&module,0,10000)==0); assert(env.heap.allocations==4 && env.heap.cursor-begin==native_cursor); assert(get(memory,0)==object); for(unsigned i=19;i<32;++i) assert(get(memory,i*8)==registers[i]); const unsigned fields[]={8,16,24,56,64,72}; for(unsigned i=0;isize;++i) { if(i>=object && i=begin && i=ram->size-368 && isize-256) continue; assert(memory[i]==0xa5); } } /* Each original allocation can fail without returning a forged pointer. */ const uint64_t lengths[]={0,23,24,2079,2080,2087,2088,2103,2104}; for(unsigned i=0;isize); assert(factorio_guest_heap_init(&env.heap,memory,ram->size,131072,131072+lengths[i])==0); uint64_t registers[32]={0};registers[0]=4096;registers[31]=ram->size-256; memcpy(memory,registers,sizeof(registers)); assert(w2c_factorio__target_run(&module,0,10000)==(lengths[i]<2104 ? 5u:0u)); for(uint64_t j=131072+lengths[i];j<196608;++j) assert(memory[j]==0xa5); } assert(w2c_factorio__target_run(&module,1048576-255,10000)==2); assert(w2c_factorio__target_run(&module,UINT32_MAX,10000)==2); uint64_t registers[32]={0};registers[0]=4096;registers[31]=ram->size-256; memcpy(memory,registers,sizeof(registers)); assert(w2c_factorio__target_run(&module,0,0)==3); /* Heap input arithmetic is checked before any addition or narrowing. */ FactorioGuestHeap heap; assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,196608)==0); FactorioGuestHeap before=heap;uint64_t address=123; assert(factorio_guest_heap_allocate(&heap,UINT64_MAX,&address)==1); assert(address==123 && memcmp(&before,&heap,sizeof(heap))==0); assert(factorio_guest_heap_allocate(&heap,0,&address)==0 && address==131072); assert(factorio_guest_heap_allocate(&heap,0,&address)==0 && address==131088); assert(factorio_guest_heap_init(&heap,memory,ram->size,0,196608)==2); assert(factorio_guest_heap_init(&heap,memory,ram->size,131073,196608)==2); assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,UINT64_MAX)==2); assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,131071)==2); assert(factorio_guest_heap_init(&heap,memory,ram->size,131072,196608)==0); heap.cursor=heap.end+1;address=123; assert(factorio_guest_heap_allocate(&heap,8,&address)==2 && address==123); heap.cursor=131072;heap.allocations=UINT32_MAX; assert(factorio_guest_heap_allocate(&heap,8,&address)==2 && address==123); FactorioTargetProbe report={0}; assert(factorio_target_probe(&report)==0); assert(report.allocations==4 && report.initialized_targets==64 && report.heap_bytes==2104); assert(factorio_target_probe(NULL)==2); wasm2c_factorio__target_free(&module);wasm_rt_free(); puts("PASS: 512 original ARM64 object graphs, 64 targets each, relocated pointers, heap exhaustion, output/register/memory guards"); return 0; }