wip: extend M5 ownership tests and cleanup emission
조건부 이동, 이중 destroy, 직접 drop 호출에 대한 실패 fixture를 추가하고 runtime harness와 test-dos.bat를 그에 맞춰 갱신한다. M5는 아직 완료가 아니다. 모든 경로에서 정확히 1회 cleanup, defer/drop의 선언 역순 병합, try 전파 경로 cleanup, MaybeMoved 런타임 live flag, struct drop과 필드 역순 drop, 분기/루프 상태 합류, 누수/이중해제 카운터 harness가 남아 있다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012PQm6oAvWX4Lp3iSN5AHGT
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
unit m5_bad_conditional;
|
||||
|
||||
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||
|
||||
fn bad(p: ^i32, flag: bool) -> void {
|
||||
if flag { take(p); }
|
||||
p.^ = 3;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
unit m5_bad_double;
|
||||
|
||||
fn bad(p: ^i32) -> void {
|
||||
mem.destroy(p);
|
||||
mem.destroy(p);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
unit m5_bad_drop;
|
||||
|
||||
struct Box {
|
||||
value: i32,
|
||||
fn drop(self: &mut Self) { self.value = 0; }
|
||||
}
|
||||
|
||||
fn bad() -> void {
|
||||
var b: Box = Box{ value: 1 };
|
||||
b.drop();
|
||||
}
|
||||
@@ -1,9 +1,52 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#undef malloc
|
||||
#undef free
|
||||
|
||||
extern long fe_m5_runtime_run(long mode);
|
||||
extern void fe_m5_runtime_conditional(unsigned char flag);
|
||||
extern void fe_m5_runtime_argument_cleanup(void);
|
||||
|
||||
static void *live_ptrs[64];
|
||||
static unsigned live_count;
|
||||
static unsigned alloc_count;
|
||||
static unsigned free_count;
|
||||
static unsigned double_free_count;
|
||||
|
||||
void *m5_malloc(size_t size)
|
||||
{
|
||||
void *p = malloc(size);
|
||||
if (p && live_count < 64) live_ptrs[live_count++] = p;
|
||||
if (p) ++alloc_count;
|
||||
return p;
|
||||
}
|
||||
|
||||
void m5_free(void *p)
|
||||
{
|
||||
unsigned i;
|
||||
if (!p) return;
|
||||
for (i = 0; i < live_count; ++i) {
|
||||
if (live_ptrs[i] == p) {
|
||||
live_ptrs[i] = live_ptrs[--live_count];
|
||||
++free_count;
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
++double_free_count;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (fe_m5_runtime_run(0) != 0) return 1;
|
||||
if (fe_m5_runtime_run(1) != 9) return 2;
|
||||
if (fe_m5_runtime_run(2) != 0) return 3;
|
||||
fe_m5_runtime_conditional(0);
|
||||
fe_m5_runtime_conditional(1);
|
||||
fe_m5_runtime_argument_cleanup();
|
||||
if (double_free_count != 0) return 4;
|
||||
if (live_count != 0) return 5;
|
||||
if (alloc_count != free_count) return 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+14
-6
@@ -1,5 +1,7 @@
|
||||
unit m5_runtime;
|
||||
|
||||
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||
|
||||
pub fn run(mode: i32) -> i32 {
|
||||
var p: ^i32 = try mem.create(i32);
|
||||
defer { mem.destroy(p); }
|
||||
@@ -9,11 +11,17 @@ pub fn run(mode: i32) -> i32 {
|
||||
p.^ = 9;
|
||||
return p.^;
|
||||
}
|
||||
while true {
|
||||
break;
|
||||
}
|
||||
if mode == 2 {
|
||||
return 0;
|
||||
}
|
||||
while true { break; }
|
||||
if mode == 2 { return 0; }
|
||||
return p.^ - 7;
|
||||
}
|
||||
|
||||
pub fn conditional(flag: bool) -> void {
|
||||
var p: ^i32 = try mem.create(i32);
|
||||
if flag { take(p); }
|
||||
}
|
||||
|
||||
pub fn argument_cleanup() -> void {
|
||||
let p: ^i32 = try mem.create(i32);
|
||||
take(p);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user