m7_emit_call reimplements call emission and only carried over mem.destroy and
mem.replace, so every mem.create/mem.alloc_slice fell through to the generic
member path and emitted `fe_missing.create(0)`. wcc386 does not diagnose that
-- it terminates with exit 255, which wcl386 reports as "Unable to invoke
wcc386.exe" with no message at all.
The breakage covered all 17 allocation sites in m5/runtime.fe, and it was
invisible because m5-owned and m5-defer only emit C; m5-runtime is the one M5
fixture that compiles and links what was generated.
Also make runtime.fe legal: `run` used `try` while returning i32, which SPEC
allows only in a function returning an error union. It is `-> !i32` now, which
M7 accepts because contextual success construction lands with it, and
runtime.c takes the { error, value } struct the error union lowers to.
Found by calling wcc386 directly instead of through wcl386, which is the only
way to see a compiler crash here.
M1-M7: 183 passed.
102 lines
3.5 KiB
C
102 lines
3.5 KiB
C
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
|
|
#undef malloc
|
|
#undef free
|
|
|
|
extern void *malloc(size_t size);
|
|
extern void free(void *p);
|
|
|
|
/* `run` returns !i32, which lowers to { error, value }. */
|
|
struct fe_result_value_9 { unsigned short e; long v; };
|
|
extern struct fe_result_value_9 fe_m5_runtime_run(long mode);
|
|
extern unsigned short fe_m5_runtime_conditional(unsigned char flag);
|
|
extern unsigned short fe_m5_runtime_argument_cleanup(void);
|
|
extern unsigned short fe_m5_runtime_owned_slice(unsigned long n);
|
|
extern unsigned short fe_m5_runtime_replace_field(void);
|
|
extern unsigned short fe_m5_runtime_loop_cleanup(void);
|
|
extern unsigned short fe_m5_runtime_try_cleanup(void);
|
|
extern unsigned short fe_m5_runtime_field_order(void);
|
|
extern unsigned short fe_m5_runtime_defer_order(void);
|
|
extern unsigned short fe_m5_runtime_match_cleanup(unsigned char flag);
|
|
extern unsigned short fe_m5_runtime_close_once(void);
|
|
extern unsigned short fe_m5_runtime_reassign_struct(void);
|
|
|
|
static void *live_ptrs[64];
|
|
static unsigned live_count;
|
|
static unsigned alloc_count;
|
|
static unsigned free_count;
|
|
static unsigned double_free_count;
|
|
static long fail_after = -1;
|
|
static unsigned malloc_attempts;
|
|
static int track_order;
|
|
static void *order_ptrs[2];
|
|
static unsigned order_allocs;
|
|
static unsigned order_frees;
|
|
static unsigned order_bad;
|
|
|
|
void *m5_malloc(size_t size)
|
|
{
|
|
void *p;
|
|
if (fail_after >= 0 && (long)malloc_attempts++ == fail_after) return 0;
|
|
p = malloc(size);
|
|
if (p && live_count < 64) live_ptrs[live_count++] = p;
|
|
if (p) ++alloc_count;
|
|
if (p && track_order && order_allocs < 2) order_ptrs[order_allocs++] = p;
|
|
return p;
|
|
}
|
|
|
|
void m5_free(void *p)
|
|
{
|
|
unsigned i;
|
|
if (!p) return;
|
|
for (i = 0; i < live_count; ++i) {
|
|
if (live_ptrs[i] == p) {
|
|
if (track_order && order_frees < 2 &&
|
|
p != order_ptrs[1-order_frees]) ++order_bad;
|
|
if (track_order && order_frees < 2) ++order_frees;
|
|
live_ptrs[i] = live_ptrs[--live_count];
|
|
++free_count;
|
|
free(p);
|
|
return;
|
|
}
|
|
}
|
|
++double_free_count;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
struct fe_result_value_9 r;
|
|
r = fe_m5_runtime_run(0); if (r.e != 0 || r.v != 0) return 1;
|
|
r = fe_m5_runtime_run(1); if (r.e != 0 || r.v != 9) return 2;
|
|
r = fe_m5_runtime_run(2); if (r.e != 0 || r.v != 0) return 3;
|
|
if (fe_m5_runtime_conditional(0) != 0) return 4;
|
|
if (fe_m5_runtime_conditional(1) != 0) return 5;
|
|
if (fe_m5_runtime_argument_cleanup() != 0) return 6;
|
|
if (fe_m5_runtime_owned_slice(17) != 0) return 7;
|
|
if (fe_m5_runtime_replace_field() != 0) return 8;
|
|
if (fe_m5_runtime_loop_cleanup() != 0) return 9;
|
|
fail_after=1;
|
|
malloc_attempts=0;
|
|
if (fe_m5_runtime_try_cleanup() == 0) return 10;
|
|
fail_after=-1;
|
|
track_order=1;
|
|
order_allocs=order_frees=order_bad=0;
|
|
if (fe_m5_runtime_field_order() != 0) return 11;
|
|
track_order=0;
|
|
if (order_allocs != 2 || order_frees != 2 || order_bad != 0) return 12;
|
|
track_order=1;
|
|
order_allocs=order_frees=order_bad=0;
|
|
if (fe_m5_runtime_defer_order() != 0) return 13;
|
|
track_order=0;
|
|
if (order_allocs != 2 || order_frees != 2 || order_bad != 0) return 14;
|
|
if (fe_m5_runtime_match_cleanup(0) != 0) return 15;
|
|
if (fe_m5_runtime_match_cleanup(1) != 0) return 16;
|
|
if (fe_m5_runtime_close_once() != 0) return 17;
|
|
if (fe_m5_runtime_reassign_struct() != 0) return 18;
|
|
if (double_free_count != 0) return 19;
|
|
if (live_count != 0) return 20;
|
|
if (alloc_count != free_count) return 21;
|
|
return 0;
|
|
}
|