From f087aa88e22a815fa0d00f65d96e2ec6bcd93b21 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 27 Aug 2026 10:16:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=EF=BC=8C=E5=8F=AF=E8=87=AA?= =?UTF-8?q?=E4=B8=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _list.vp | 5 + _variant.vp | 2 +- ast/stmts.vp | 2 +- builtins.vp | 12 ++ hashlib/__md5.vp | 4 +- hashlib/__sha1.vp | 8 +- hashlib/__sha256.vp | 2 +- json/__init__.vp | 28 ++--- json/__parser.vp | 20 ++-- json/__writer.vp | 16 +-- llvmlite/__builder.vp | 18 ++- llvmlite/__init__.vp | 9 +- llvmlite/__module.vp | 33 +++++- llvmlite/__values.vp | 2 +- llvmlite/__verify.vp | 18 ++- memhub.vp | 266 ++++++++++++++++++++++++++++++++++++++++-- posix.vp | 63 +++++----- stdarg.vp | 8 +- stdio.vp | 16 +-- stdlib.vp | 12 +- string.vp | 40 +++---- sys.vp | 8 +- 22 files changed, 459 insertions(+), 133 deletions(-) diff --git a/_list.vp b/_list.vp index 5e60cf6..4c38202 100644 --- a/_list.vp +++ b/_list.vp @@ -1,8 +1,13 @@ import t, c import memhub import string +import stdio from stdint import * +# [LISTDBG] 诊断(用后移除):list.__init__ 打印初始化结果、append 首次 +# (Count==0) 打印 self/Data,配合 CTORDBG 定位二代编 SlotsBugTest cargs(list) +# 头覆盖。默认静默——由命令行 --enable-debug-log 开启(memhub.set_debug_log) + class list[T]: """Heap-allocated dynamic list container backed by memhub.MemManager polymorphic allocator. diff --git a/_variant.vp b/_variant.vp index 31273dc..4da7f37 100644 --- a/_variant.vp +++ b/_variant.vp @@ -2,7 +2,7 @@ import t, c from stdint import * # Variant type tags (fixed enumeration + custom pointer type) -VARIANT_NONE: t.CDefine = 0 # Untyped / null value +VARIANT_NONE: t.CDefine = 0 # Untyped / null value VARIANT_INT: t.CDefine = 1 # int (i64) VARIANT_FLOAT: t.CDefine = 2 # float (f32) VARIANT_DOUBLE: t.CDefine = 3 # double (f64) diff --git a/ast/stmts.vp b/ast/stmts.vp index 569646a..fccfab8 100644 --- a/ast/stmts.vp +++ b/ast/stmts.vp @@ -6,7 +6,7 @@ from .base import ( AST, Stmt, ASTKind, ASTCtx, OpKind, _init_ast, _copy_str, _set_parent_list, _emit, _emit_str, _emit_int, _dump_list, - FLAG_IS_ASYNC, + FLAG_IS_ASYNC, _op_name ) diff --git a/builtins.vp b/builtins.vp index 5296c61..1fdd467 100644 --- a/builtins.vp +++ b/builtins.vp @@ -4,6 +4,8 @@ import t # 内置函数(Python 语义,自动与 builtins 关联,无需显式 import) # ord: 字符 → ASCII 码(int) # chr: ASCII 码 → 字符(t.CChar) +# min/max: 数值比较取小/大值(double 参数,int/float 实参经 +# coerce_to_type 无损提升;返回值由调用侧 coerce 到目标类型) # ============================================================ def ord(s: t.CChar) -> int: @@ -11,3 +13,13 @@ def ord(s: t.CChar) -> int: def chr(i: int) -> t.CChar: return i + +def min(a: double, b: double) -> double: + if a < b: + return a + return b + +def max(a: double, b: double) -> double: + if a > b: + return a + return b diff --git a/hashlib/__md5.vp b/hashlib/__md5.vp index d98680f..4cf5332 100644 --- a/hashlib/__md5.vp +++ b/hashlib/__md5.vp @@ -14,7 +14,7 @@ def md5_G(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x def md5_H(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return x ^ y ^ z def md5_I(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return y ^ (x | ~z) # Circular left shift -def md5_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) +def md5_rotl(x: t.CUInt32T, n: int) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) # MD5 constant table md5_T: t.CArray[t.CUInt32T, 64] = [ @@ -28,7 +28,7 @@ md5_T: t.CArray[t.CUInt32T, 64] = [ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ] -md5_S: t.CArray[t.CInt, 64] = [ +md5_S: t.CArray[int, 64] = [ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, diff --git a/hashlib/__sha1.vp b/hashlib/__sha1.vp index fdd28ae..21ecab7 100644 --- a/hashlib/__sha1.vp +++ b/hashlib/__sha1.vp @@ -9,7 +9,7 @@ import t, c SHA1_BLOCK_LEN: t.CDefine = 64 SHA1_DIGEST_LEN: t.CDefine = 20 -def sha1_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) +def sha1_rotl(x: t.CUInt32T, n: int) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) # 3-round logical functions def sha1_f1(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return (b & c) | (~b & d) def sha1_f2(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return b ^ c ^ d @@ -22,7 +22,7 @@ class sha1: count: t.CUInt64T buf: t.CArray[t.CUInt8T, SHA1_BLOCK_LEN] def __init__(self): - memset(self.buf, 0, SHA1_BLOCK_LEN) + string.memset(self.buf, 0, SHA1_BLOCK_LEN) self.state[0] = 0x67452301 self.state[1] = 0xefcdab89 self.state[2] = 0x98badcfe @@ -103,10 +103,10 @@ class sha1: self.buf[idx] = 0x80 idx += 1 if idx > SHA1_BLOCK_LEN - 8: - memset(self.buf + idx, 0, SHA1_BLOCK_LEN - idx) + string.memset(self.buf + idx, 0, SHA1_BLOCK_LEN - idx) self.transform(self.buf) idx = 0 - memset(self.buf + idx,0,SHA1_BLOCK_LEN-8-idx) + string.memset(self.buf + idx,0,SHA1_BLOCK_LEN-8-idx) bits: t.CUInt64T = self.count << 3 # SHA1 big-endian write length for i in range(8): diff --git a/hashlib/__sha256.vp b/hashlib/__sha256.vp index 4330bd5..c04af58 100644 --- a/hashlib/__sha256.vp +++ b/hashlib/__sha256.vp @@ -1,5 +1,5 @@ -import t, c import string +import t, c # ============================================== diff --git a/json/__init__.vp b/json/__init__.vp index b937cea..49f6e23 100644 --- a/json/__init__.vp +++ b/json/__init__.vp @@ -21,13 +21,13 @@ JSON_OBJECT: t.CDefine = 6 # 使用 mpool 分配:JsonValue(pool) 从池中分配内存 # ============================================================ class JsonValue: - vtype: t.CInt - bool_val: t.CInt + vtype: int + bool_val: int int_val: t.CInt64T float_val: t.CDouble - str_val: t.CChar | t.CPtr + str_val: str next: 'JsonValue' | t.CPtr - key: t.CChar | t.CPtr + key: str child: 'JsonValue' | t.CPtr child_count: t.CSizeT @@ -38,7 +38,7 @@ class JsonValue: string.memset(ptr, 0, JsonValue.__sizeof__()) return ptr - def type(self) -> t.CInt: + def type(self) -> int: return self.vtype def is_null(self) -> bool: @@ -71,13 +71,13 @@ class JsonValue: def as_float(self) -> t.CDouble: return self.float_val - def as_string(self) -> t.CChar | t.CPtr: + def as_string(self) -> str: return self.str_val def __len__(self) -> t.CSizeT: return self.child_count - def __getitem__(self, key: t.CChar | t.CPtr) -> 'JsonValue' | t.CPtr: + def __getitem__(self, key: str) -> 'JsonValue' | t.CPtr: """Python风格取值:v["key"] 取对象字段""" if self.vtype != JSON_OBJECT: return None @@ -91,7 +91,7 @@ class JsonValue: cur = cur.next return None - def __setitem__(self, key: t.CChar | t.CPtr, val: 'JsonValue' | t.CPtr): + def __setitem__(self, key: str, val: 'JsonValue' | t.CPtr): """Python风格赋值:v["key"] = val""" if self.vtype != JSON_OBJECT or key == None or val == None: return @@ -110,7 +110,7 @@ class JsonValue: cur = cur.next # key 不存在,追加新子节点 klen: t.CSizeT = string.strlen(key) - kbuf: t.CChar | t.CPtr = self._pool_alloc(klen + 1) + kbuf: str = self._pool_alloc(klen + 1) if kbuf != None: string.memcpy(kbuf, key, klen + 1) val.key = kbuf @@ -129,7 +129,7 @@ class JsonValue: i += 1 return None - def _pool_alloc(self, size: t.CSizeT) -> t.CChar | t.CPtr: + def _pool_alloc(self, size: t.CSizeT) -> str: """内部方法:从当前对象的 mpool 分配内存(预留,暂返回 None)""" return None @@ -175,13 +175,13 @@ def float_val(pool: memhub.MemManager | t.CPtr, val: t.CDouble) -> JsonValue | t v.float_val = val return v -def string_val(pool: memhub.MemManager | t.CPtr, val: t.CChar | t.CPtr) -> JsonValue | t.CPtr: +def string_val(pool: memhub.MemManager | t.CPtr, val: str) -> JsonValue | t.CPtr: v: JsonValue | t.CPtr = JsonValue(pool) if v == None: return None v.vtype = JSON_STRING if val != None: slen: t.CSizeT = string.strlen(val) - buf: t.CChar | t.CPtr = pool.alloc(slen + 1) + buf: str = pool.alloc(slen + 1) if buf != None: string.memcpy(buf, val, slen + 1) v.str_val = buf @@ -206,7 +206,7 @@ def array_append(pool: memhub.MemManager | t.CPtr, arr: JsonValue | t.CPtr, item arr._append_child(item) # 向对象设置键值对 -def object_set(pool: memhub.MemManager | t.CPtr, obj: JsonValue | t.CPtr, key: t.CChar | t.CPtr, val: JsonValue | t.CPtr): +def object_set(pool: memhub.MemManager | t.CPtr, obj: JsonValue | t.CPtr, key: str, val: JsonValue | t.CPtr): if obj == None or key == None or val == None: return if obj.vtype != JSON_OBJECT: return cur: JsonValue | t.CPtr = obj.child @@ -223,7 +223,7 @@ def object_set(pool: memhub.MemManager | t.CPtr, obj: JsonValue | t.CPtr, key: t return cur = cur.next klen: t.CSizeT = string.strlen(key) - kbuf: t.CChar | t.CPtr = pool.alloc(klen + 1) + kbuf: str = pool.alloc(klen + 1) if kbuf != None: string.memcpy(kbuf, key, klen + 1) val.key = kbuf diff --git a/json/__parser.vp b/json/__parser.vp index 2c9a300..bc6ef1f 100644 --- a/json/__parser.vp +++ b/json/__parser.vp @@ -10,12 +10,12 @@ from . import ( class ParseState: - src: t.CChar | t.CPtr + src: str pos: t.CSizeT len: t.CSizeT pool: memhub.MemManager | t.CPtr - def __init__(self, src: t.CChar | t.CPtr, pool: memhub.MemManager | t.CPtr): + def __init__(self, src: str, pool: memhub.MemManager | t.CPtr): self.src = src self.pos = 0 self.len = string.strlen(src) if src != None else 0 @@ -52,7 +52,7 @@ def _expect(s: ParseState | t.CPtr, ch: t.CChar) -> bool: return True -def _parse_string(s: ParseState | t.CPtr) -> t.CChar | t.CPtr: +def _parse_string(s: ParseState | t.CPtr) -> str: if _peek(s) != '"': return None _advance(s) @@ -69,7 +69,7 @@ def _parse_string(s: ParseState | t.CPtr) -> t.CChar | t.CPtr: slen += 1 s.pos += 1 - buf: t.CChar | t.CPtr = s.pool.alloc(slen + 1) + buf: str = s.pool.alloc(slen + 1) if buf == None: return None @@ -147,7 +147,7 @@ def _parse_number(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: break num_len: t.CSizeT = s.pos - start - buf: t.CChar | t.CPtr = s.pool.alloc(num_len + 1) + buf: str = s.pool.alloc(num_len + 1) if buf == None: return null(s.pool) @@ -173,7 +173,7 @@ def _parse_value(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: ch: t.CChar = _peek(s) if ch == '"': - sv: t.CChar | t.CPtr = _parse_string(s) + sv: str = _parse_string(s) return string_val(s.pool, sv) if ch == '{': @@ -249,12 +249,12 @@ def _parse_object(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: return obj _skip_whitespace(s) - key: t.CChar | t.CPtr = _parse_string(s) + key: str = _parse_string(s) _expect(s, ':') val: JsonValue | t.CPtr = _parse_value(s) if key != None and val != None: klen: t.CSizeT = string.strlen(key) - kbuf: t.CChar | t.CPtr = s.pool.alloc(klen + 1) + kbuf: str = s.pool.alloc(klen + 1) if kbuf != None: string.memcpy(kbuf, key, klen + 1) val.key = kbuf @@ -273,7 +273,7 @@ def _parse_object(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: val = _parse_value(s) if key != None and val != None: klen2: t.CSizeT = string.strlen(key) - kbuf2: t.CChar | t.CPtr = s.pool.alloc(klen2 + 1) + kbuf2: str = s.pool.alloc(klen2 + 1) if kbuf2 != None: string.memcpy(kbuf2, key, klen2 + 1) val.key = kbuf2 @@ -283,7 +283,7 @@ def _parse_object(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: return obj -def parse(pool: memhub.MemManager | t.CPtr, src: t.CChar | t.CPtr) -> JsonValue | t.CPtr: +def parse(pool: memhub.MemManager | t.CPtr, src: str) -> JsonValue | t.CPtr: """解析 JSON 字符串,返回 JsonValue 树""" if src == None: return null(pool) diff --git a/json/__writer.vp b/json/__writer.vp index 4b6435b..8a493a0 100644 --- a/json/__writer.vp +++ b/json/__writer.vp @@ -9,17 +9,17 @@ from . import ( ) -def _write_char(buf: t.CChar | t.CPtr, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT: +def _write_char(buf: str, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT: buf[pos] = ch return pos + 1 -def _write_str(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: +def _write_str(buf: str, pos: t.CSizeT, s: str) -> t.CSizeT: if s == None: return pos slen: t.CSizeT = string.strlen(s) string.memcpy(t.CChar(t.CUInt64T(buf) + pos, t.CPtr), s, slen) return pos + slen -def _write_string_escaped(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: +def _write_string_escaped(buf: str, pos: t.CSizeT, s: str) -> t.CSizeT: if s == None: pos = _write_str(buf, pos, "null") return pos @@ -45,7 +45,7 @@ def _write_string_escaped(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.C return pos -def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, pool: memhub.MemManager | t.CPtr) -> t.CSizeT: +def _write_value(buf: str, pos: t.CSizeT, val: JsonValue | t.CPtr, pool: memhub.MemManager | t.CPtr) -> t.CSizeT: if val == None: pos = _write_str(buf, pos, "null") return pos @@ -60,13 +60,13 @@ def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, pos = _write_str(buf, pos, "false") elif val.vtype == JSON_INT: - tmp: t.CChar | t.CPtr = pool.alloc(32) + tmp: str = pool.alloc(32) if tmp != None: snprintf(tmp, 32, "%lld", val.int_val) pos = _write_str(buf, pos, tmp) elif val.vtype == JSON_FLOAT: - tmp2: t.CChar | t.CPtr = pool.alloc(32) + tmp2: str = pool.alloc(32) if tmp2 != None: snprintf(tmp2, 32, "%.6g", val.float_val) pos = _write_str(buf, pos, tmp2) @@ -109,9 +109,9 @@ def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, return pos -def write(pool: memhub.MemManager | t.CPtr, val: JsonValue | t.CPtr, pretty: bool) -> t.CChar | t.CPtr: +def write(pool: memhub.MemManager | t.CPtr, val: JsonValue | t.CPtr, pretty: bool) -> str: """将 JsonValue 序列化为 JSON 字符串""" - buf: t.CChar | t.CPtr = pool.alloc(4096) + buf: str = pool.alloc(4096) if buf == None: return None end_pos: t.CSizeT = _write_value(buf, 0, val, pool) diff --git a/llvmlite/__builder.vp b/llvmlite/__builder.vp index 0de1afc..da9cfc5 100644 --- a/llvmlite/__builder.vp +++ b/llvmlite/__builder.vp @@ -1822,10 +1822,25 @@ def build_inline_asm(builder: IRBuilder | t.CPtr, ret_ty: LLVMType | t.CPtr, # ============================================================ # 内部辅助 # ============================================================ +# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位, +# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 +# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 +_g_last_dst: t.CUInt64T = 0 +_g_last_pos: t.CSizeT = 0 + def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): """将 C 字符串 src 追加到 dst 末尾""" + global _g_last_dst, _g_last_pos if dst is None or src is None: return - dlen: t.CSizeT = string.strlen(dst) + dlen: t.CSizeT = 0 + if _g_last_dst == t.CUInt64T(dst): + dlen = _g_last_pos + # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 + if dlen > 0 and dst[0] == '\0': + dlen = 0 + else: + dlen = string.strlen(dst) + _g_last_dst = t.CUInt64T(dst) # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: @@ -1838,3 +1853,4 @@ def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPt dst[dlen + i] = src[i] i += 1 dst[dlen + i] = '\0' + _g_last_pos = dlen + i diff --git a/llvmlite/__init__.vp b/llvmlite/__init__.vp index 9ee22bf..c5eb10d 100644 --- a/llvmlite/__init__.vp +++ b/llvmlite/__init__.vp @@ -149,7 +149,14 @@ def const_int(pool: memhub.MemBuddy | t.CPtr, bits: t.CInt, # 创建名字文本 name: t.CChar | t.CPtr = pool.alloc(32) if name is None: return None - viperlib.snprintf(name, 32, "%lld", val) + # LLVM i64 字面量范围不含 INT64_MIN(-9223372036854775808):该值必须 + # 用无符号位模式 9223372036854775808 表示(LLVM 接受),否则 opt 解析 + # "-9223372036854775808" 报 expected value token(二代编 viperlib.vp + # u_num=0x8000000000000000 崩溃根因;gen1/TPC 即输出无符号位模式)。 + if bits == 64 and val == -9223372036854775807 - 1: + viperlib.snprintf(name, 32, "9223372036854775808") + else: + viperlib.snprintf(name, 32, "%lld", val) return ConstInt(pool, ty, val, name) diff --git a/llvmlite/__module.vp b/llvmlite/__module.vp index 3d657fc..df3c7fa 100644 --- a/llvmlite/__module.vp +++ b/llvmlite/__module.vp @@ -526,7 +526,18 @@ def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr, case _: _scan_type_for_cross_module_refs(pool, mod, pointee, depth + 1) case LLVMType.Struct(sfields2, sfcount2, sname2): - # 顶层结构体(非指针):递归扫描字段 + # 顶层结构体(非指针):递归扫描字段,并补 opaque 声明。 + # 此前只对 Ptr(Struct) 添加 opaque,裸 Struct(值类型,如 + # 数组元素 [7 x gdt_entry] 的 gdt_entry)引用时无任何类型定义 + # → llc "use of undefined type named 'sha1.gdt_entry'" + # (fpu/fat32 合并 IR external global 根因)。值类型引用 + # 同样需要类型存在(opaque 即可);模块已有完整定义时 + # _is_type_defined_in_module 命中,不重复添加。 + if sname2 is not None and string.strchr(sname2, 46) is not None: + if _is_type_defined_in_module(mod, sname2) == 0: + opaque_ty2: LLVMType | t.CPtr = Struct(pool, None, -1, sname2) + if opaque_ty2 is not None: + module_add_named_type(mod, pool, opaque_ty2) if sfields2 is not None: fld2: ParamNode | t.CPtr = sfields2 fld2_steps: t.CSizeT = 0 @@ -691,10 +702,25 @@ def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT, # ============================================================ # 内部辅助 # ============================================================ +# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位, +# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 +# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 +_g_last_dst: t.CUInt64T = 0 +_g_last_pos: t.CSizeT = 0 + def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): """将 C 字符串 src 追加到 dst 末尾""" + global _g_last_dst, _g_last_pos if dst is None or src is None: return - dlen: t.CSizeT = string.strlen(dst) + dlen: t.CSizeT = 0 + if _g_last_dst == t.CUInt64T(dst): + dlen = _g_last_pos + # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 + if dlen > 0 and dst[0] == '\0': + dlen = 0 + else: + dlen = string.strlen(dst) + _g_last_dst = t.CUInt64T(dst) # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: @@ -706,4 +732,5 @@ def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPt while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 - dst[dlen + i] = '\0' \ No newline at end of file + dst[dlen + i] = '\0' + _g_last_pos = dlen + i \ No newline at end of file diff --git a/llvmlite/__values.vp b/llvmlite/__values.vp index af44781..f488587 100644 --- a/llvmlite/__values.vp +++ b/llvmlite/__values.vp @@ -104,7 +104,7 @@ def ConstFloat(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, # 用 CRT stdio.snprintf: viperlib 自实现 %g 有小数位反转 bug。 f_bits: t.CInt = 64 match ty: - case llvmlite.LLVMType.Float(ftb): + case LLVMType.Float(ftb): f_bits = ftb fv_bits: t.CUInt64T = 0 c.Load(c.Addr(fv_bits), c.Addr(val)) diff --git a/llvmlite/__verify.vp b/llvmlite/__verify.vp index 1c21e86..04f7733 100644 --- a/llvmlite/__verify.vp +++ b/llvmlite/__verify.vp @@ -78,10 +78,25 @@ def _report_error(result: VerifyResult | t.CPtr, code: t.CInt, msg: t.CChar | t. _append_cstr(result.ErrorBuf, result.ErrorBufSize, "\n") +# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位, +# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 +# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 +_g_last_dst: t.CUInt64T = 0 +_g_last_pos: t.CSizeT = 0 + def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): """将 src 追加到 dst 末尾""" + global _g_last_dst, _g_last_pos if dst is None or src is None: return - dlen: t.CSizeT = string.strlen(dst) + dlen: t.CSizeT = 0 + if _g_last_dst == t.CUInt64T(dst): + dlen = _g_last_pos + # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 + if dlen > 0 and dst[0] == '\0': + dlen = 0 + else: + dlen = string.strlen(dst) + _g_last_dst = t.CUInt64T(dst) # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: @@ -94,6 +109,7 @@ def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPt dst[dlen + i] = src[i] i += 1 dst[dlen + i] = '\0' + _g_last_pos = dlen + i # ============================================================ diff --git a/memhub.vp b/memhub.vp index ff540d4..b02dd72 100644 --- a/memhub.vp +++ b/memhub.vp @@ -30,6 +30,29 @@ MEMBUDDY_HEADER_SIZE: t.CDefine = 8 # "崩溃点漂移/事发地遥远"变成"确定性定位到越界写发生的文件" MEMBUDDY_CANARY: t.CDefine = 8 +# 分配守卫(诊断,SlotsBugTest 二代编 list 头覆盖排查): +# alloc 时把用户数据区填充 0xCD 哨兵。若对象初始化(list.__init__ 等) +# 未执行,其字段保持 0xCDCD...,CTORDBG/VDBG 打印字段时一眼可辨 +# "未初始化(0xCDCD)" 与 "被覆盖(其他值)"。0=关闭(性能),1=开启。 +MEMBUDDY_FILL_GUARD: t.CDefine = 1 +MEMBUDDY_FILL_PATTERN: t.CDefine = 0xCD + +# [DET] 分配检测(alloc 前后 2 字节 0xCDCD 标记 + 记录表探测越界写): +# 检测模式(MemBuddy(..., detection=1))下每次 alloc 布局为 +# [0xCDCD][请求大小内存][0xCDCD](实际比请求多 4 字节) +# 返回指针 = 实际用户区 + 2(前标记之后);回收时向前偏移 2 字节。 +# 每次 alloc 后探测记录表全部后标记(ptr+size 处)——被破坏 = 越界写, +# 立即汇报 ptr/size 并终止(定位"存活块被部分覆盖"的写入者, +# 如 SlotsBugTest KwEntry cargs 只写 Data/IterIndex 的块归属)。 +MEMBUDDY_DET_MARKER: t.CDefine = 0xCDCD +# 检测记录区默认大小(32MB,每条记录 {ptr u64, size u64} = 16B) +MEMBUDDY_DET_RECORD_SIZE: t.CDefine = 33554432 +# 采样周期(2 的幂):每 N 次 alloc 做一次全表扫描(分配重叠 + 探测)。 +# 记录追加本身 O(1) 不受影响;损坏是持久性的,不依赖即时扫描,采样 +# 不损失检测能力——2M 次 alloc 若每次全表 O(n) 扫描 = O(n²) 太慢 +# (用户反馈 detection 模式过慢),采样把扫描次数降为 1/N。 +MEMBUDDY_DET_PROBE_PERIOD: t.CDefine = 256 + def _canary_pattern() -> t.CUInt64T: """块尾 canary 值(0xA5A5A5A5A5A5A5A5,64 位)""" @@ -301,10 +324,28 @@ class MemBuddy(MemManager): chk_depth: t.CSizeT # 当前记录深度 chk_base: t.CVoid | t.CPtr # 记录栈起始地址(由 stdlib.malloc 分配,独立于 buddy 区) big_alloc_count: t.CSizeT # ≥8KB 大分配计数(OOM 诊断:定位大缓冲反复分配) + # [DET] 分配检测(默认关,排查越界写/存活块覆盖时开启): + # detection=1 → alloc 前后 2 字节 0xCDCD 标记 + 记录表 + 每次 alloc 后探测 + detection: t.CInt = 0 + detection_size: t.CSizeT = MEMBUDDY_DET_RECORD_SIZE + _det_arena: t.CVoid | t.CPtr = None # 记录区基址(stdlib.malloc,供 realloc 扩容) + _det_records: t.CUInt64T | t.CPtr = None # 记录表(每 2×u64 = 1 条:{ptr, size}) + _det_count: t.CSizeT = 0 # 已记录条数 + _det_cap: t.CSizeT = 0 # 记录容量(条) - def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT): + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT, + detection: t.CInt = 0): self.base = base self.size = size + self.detection = detection + # 显式赋值(不能依赖字段默认值——TPC 类字段默认值对 CDefine 常量 + # 可能不生效,垃圾 detection_size → malloc(垃圾) 1-byte 记录区 → + # 扩容 realloc double-free,ASAN 已捕获) + self.detection_size = MEMBUDDY_DET_RECORD_SIZE + self._det_arena = None + self._det_records = None + self._det_count = 0 + self._det_cap = 0 self.max_order = 0 self.free_lists = None self.lock_val = 0 @@ -377,6 +418,17 @@ class MemBuddy(MemManager): rem -= blk self.usable_size = used_area + # [DET] 分配检测记录区:stdlib.malloc 独立分配(不占用 buddy 区, + # 与 chk_stack 同策略)。容量 = detection_size // 16(每条 {ptr,size})。 + if detection != 0: + det_arena: t.CVoid | t.CPtr = t.CVoid( + stdlib.malloc(self.detection_size), t.CPtr) + if det_arena is not None: + self._det_arena = det_arena + self._det_records = (t.CUInt64T | t.CPtr)(t.CVoid(det_arena, t.CPtr)) + self._det_cap = self.detection_size // 16 + self._det_count = 0 + # === Checkpoint support === def mark(self) -> t.CSizeT: @@ -431,6 +483,12 @@ class MemBuddy(MemManager): if order < 0 or order > self.max_order: continue self._coalesce(block, order) + # [DET] reset-aware:记录表与 chk 栈等长(每次 alloc 各追加一条, + # free 只置标志不删),截断 chk_depth 必须同步截断 _det_count, + # 否则 reset 后旧记录仍标 active → 下一轮 alloc 复用同一块被 + # 误报为"分配重叠/越界写"(SlotsBugTest 7B buf + 72B Token 误报根因)。 + if self.detection != 0 and self._det_records is not None: + self._det_count = mark self._unlock() def reset_all(self): @@ -569,6 +627,9 @@ class MemBuddy(MemManager): if size != 0 and self.usable is not None: # +MEMBUDDY_CANARY:预留块尾 8 字节哨兵(用户数据区之外),越界写定位用 needed: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY + if self.detection != 0: + # [DET] 前后各 2 字节 0xCDCD 标记,实际比请求多 4 字节 + needed = needed + 4 order: t.CInt = self._order_for_size(needed) if order <= self.max_order: block: t.CVoid | t.CPtr = self._split_to_order(order) @@ -579,6 +640,13 @@ class MemBuddy(MemManager): bs: t.CSizeT = _block_size_at_order(order) c.DerefAs(t.CVoid(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), t.CVoid(_canary_pattern(), t.CPtr)) + # 分配守卫:填充用户数据区 0xCD 哨兵(未初始化检测)。 + # 调用方初始化(list.__init__ 等)覆盖前,字段保持 0xCDCD... + # CTORDBG 打印 d0-d40 时:0xCDCD...=未初始化,其他=被覆盖。 + if MEMBUDDY_FILL_GUARD != 0: + fill_size: t.CSizeT = bs - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY + if fill_size > 0: + string.memset(result, MEMBUDDY_FILL_PATTERN, fill_size) # 记录到 checkpoint 栈(供 reset_to 回收) # 栈满时 stdlib.realloc 翻倍扩容(防爆满后记录缺失 # → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题) @@ -600,13 +668,62 @@ class MemBuddy(MemManager): if self.chk_depth < self.chk_cap: self.chk_stack[self.chk_depth] = t.CUInt64T(block) self.chk_depth += 1 + if result is not None and self.detection != 0: + # [DET] 布局 [0xCDCD][请求大小内存][0xCDCD]:返回指针 = 用户区 + 2 + # (前标记之后);记录 {返回 ptr, size} 到独立记录区;随后探测全部 + # 存活块的后标记——被破坏 = 越界写,立即汇报并终止。 + base_ret_d: t.CUInt64T = t.CUInt64T(result) + m_f_d: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(base_ret_d, t.CPtr)) + m_f_d[0] = t.CUInt16T(MEMBUDDY_DET_MARKER) + tail_d: t.CUInt64T = base_ret_d + 2 + t.CUInt64T(size) + m_t_d: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(tail_d, t.CPtr)) + m_t_d[0] = t.CUInt16T(MEMBUDDY_DET_MARKER) + if self._det_records is not None: + # 采样:每 MEMBUDDY_DET_PROBE_PERIOD 次 alloc 做一次全表扫描 + # (分配重叠 + 探测),其余只追加记录(O(1))。损坏是持久性的, + # 不依赖即时扫描——2M 次 alloc 若每次全表 O(n) = O(n²) 太慢 + # (用户反馈 detection 模式过慢),采样把扫描降为 O(n²/PERIOD)。 + if (self._det_count & (MEMBUDDY_DET_PROBE_PERIOD - 1)) == 0: + # 分配重叠即时检测:新块地址是否已在 active 记录(同一块重复 + # 分配实锤——SlotsBugTest 7B buf 与 72B Token 同 ptr、cargs + # 只写 0/40 根因)。重叠 = MemBuddy free list 损坏(active 块 + # 混入 free list),在第一次重叠处拦截并打印两个 size。 + ff_d: t.CUInt64T = t.CUInt64T(1) << 63 + dup_i: t.CSizeT = 0 + while dup_i < self._det_count: + drp: t.CUInt64T = self._det_records[dup_i * 2] + drs: t.CUInt64T = self._det_records[dup_i * 2 + 1] + if drp == base_ret_d + 2 and (drs & ff_d) == 0: + stdio.printf("[DET] 分配重叠: 新alloc(size=%llu)与记录[%zu](sz=%llu)同地址 ptr=%llu(同一块重复分配,free list 损坏)\n", + t.CUInt64T(size), dup_i, drs & (ff_d - 1), base_ret_d + 2) + stdlib.exit(1) + dup_i += 1 + if self._det_count >= self._det_cap: + # 记录表满:stdlib.realloc 翻倍扩容(防 is_alive/_det_probe + # 因容量耗尽漏检——SlotsBugTest 编译 includes 超 2M 次 alloc, + # 满后新块无记录 → is_alive 误报"读取悬空") + new_cap: t.CSizeT = self._det_cap * 2 + new_rec: t.CVoid | t.CPtr = t.CVoid( + stdlib.realloc(self._det_arena, new_cap * 16), t.CPtr) + if new_rec is not None: + self._det_arena = new_rec + self._det_records = (t.CUInt64T | t.CPtr)(t.CVoid(new_rec, t.CPtr)) + self._det_cap = new_cap + if self._det_count < self._det_cap: + self._det_records[self._det_count * 2] = base_ret_d + 2 + self._det_records[self._det_count * 2 + 1] = t.CUInt64T(size) + self._det_count += 1 + if (self._det_count & (MEMBUDDY_DET_PROBE_PERIOD - 1)) == 0: + self._det_probe() + result = t.CVoid(base_ret_d + 2, t.CPtr) if result is None: # 分配失败诊断(定位"异常 size/池耗尽导致 None → 调用方解引用段错误") if size != 0 and self.usable is not None: needed2: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY order2: t.CInt = self._order_for_size(needed2) - stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu\n", - size, needed2, order2, self.max_order, self.used_bytes()) + stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu pool_base=%llu\n", + size, needed2, order2, self.max_order, self.used_bytes(), + t.CUInt64T(self.usable)) # 越界写诊断:free list 结构损坏(self_check!=0)说明有越界写穿 # 破坏块头/free list next 指针 → alloc 找不到块(used 虚高非真实耗尽) sc: t.CInt = self.self_check() @@ -630,8 +747,26 @@ class MemBuddy(MemManager): def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: self._lock() if ptr is not None: - if self._is_valid_ptr(ptr) != 0: - block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + p_eff: t.CVoid | t.CPtr = ptr + if self.detection != 0: + # [DET] 返回指针比实际用户区靠后 2 字节,回收时向前偏移 2 + p_eff = t.CVoid(t.CUInt64T(ptr) - 2, t.CPtr) + # 从记录表取本条真实 size,free 后把用户区填 0xCD(UAF 写入 + # 检测:free 后块被写穿 → 探测时 0xCD 被破坏 → 报警);记录 + # 保留并置 free 标志(探测时对仍 free 的块验证 0xCD 完整)。 + if self._det_records is not None: + ri: t.CSizeT = 0 + while ri < self._det_count: + rp: t.CUInt64T = self._det_records[ri * 2] + rs: t.CUInt64T = self._det_records[ri * 2 + 1] + if rp == t.CUInt64T(ptr) and (rs & (t.CUInt64T(1) << 63)) == 0: + if rs > 0: + string.memset(ptr, MEMBUDDY_FILL_PATTERN, rs) + self._det_records[ri * 2 + 1] = rs | (t.CUInt64T(1) << 63) + break + ri += 1 + if self._is_valid_ptr(p_eff) != 0: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(p_eff) - MEMBUDDY_HEADER_SIZE, t.CPtr) stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) stored_val: t.CUInt64T = t.CUInt64T(stored) order: t.CInt = t.CInt(stored_val >> 1) @@ -667,6 +802,10 @@ class MemBuddy(MemManager): if self.usable is None: return 0 self._rebuild_free_lists() + # [DET] reset 重建全部 free list = 全部块释放:记录表同步清空, + # 防止后续 alloc 复用旧块被误报(与 reset_to 截断同因)。 + if self.detection != 0 and self._det_records is not None: + self._det_count = 0 return 1 # realloc override: buddy system reads original order from block header; old_size is not required @@ -676,13 +815,19 @@ class MemBuddy(MemManager): if new_size == 0: self.free(ptr) return None - if self._is_valid_ptr(ptr) == 0: + p_eff: t.CVoid | t.CPtr = ptr + if self.detection != 0: + # [DET] 与 free 一致:先向前偏移 2 字节再做块级计算 + p_eff = t.CVoid(t.CUInt64T(ptr) - 2, t.CPtr) + if self._is_valid_ptr(p_eff) == 0: return None - block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(p_eff) - MEMBUDDY_HEADER_SIZE, t.CPtr) stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) stored_val: t.CUInt64T = t.CUInt64T(stored) old_order: t.CInt = t.CInt(stored_val >> 1) needed: t.CSizeT = new_size + MEMBUDDY_HEADER_SIZE + if self.detection != 0: + needed = needed + 4 # [DET] 前后标记 new_order: t.CInt = self._order_for_size(needed) if new_order <= old_order: return ptr @@ -691,10 +836,111 @@ class MemBuddy(MemManager): return ptr old_block_size: t.CSizeT = _block_size_at_order(old_order) old_data_size: t.CSizeT = old_block_size - MEMBUDDY_HEADER_SIZE - string.memcpy(new_ptr, ptr, old_data_size) + cp_len: t.CSizeT = old_data_size + if self.detection != 0: + cp_len = old_data_size - 4 # [DET] 排除前后 2 字节标记 + string.memcpy(new_ptr, ptr, cp_len) self.free(ptr) return new_ptr + # ============================================================ + # [DET] is_alive - 读取侧存活校验:ptr 是否在当前记录表的 active + # 记录中(alloc 后未 free)。返回 1=存活 / 0=悬空(不在记录或已 + # free)。detection 关闭或记录表不可用时返回 1(不拦截)。 + # 补 _det_probe 盲区:写入侧检测(标记/0xCD)拦不住 use-after-free + # 读取(如 SlotsBugTest KwEntry cargs=cl.args 悬空指向复用块)。 + # ============================================================ + def is_alive(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + if self.detection == 0: + return 1 + if self._det_records is None: + return 1 + target: t.CUInt64T = t.CUInt64T(ptr) + free_flag: t.CUInt64T = t.CUInt64T(1) << 63 + i: t.CSizeT = 0 + while i < self._det_count: + rp: t.CUInt64T = self._det_records[i * 2] + rs: t.CUInt64T = self._det_records[i * 2 + 1] + if rp == target and (rs & free_flag) == 0: + return 1 + i += 1 + return 0 + + # ============================================================ + # [DET] _det_probe - 分配检测探测:遍历记录表,验证每个存活块的 + # 后标记(返回 ptr + size 处 2 字节)仍为 0xCDCD。 + # 被破坏 = 越界写(数据区写穿),立即汇报 ptr/size 并终止—— + # 把"随机崩溃/字段被覆盖"变成"确定性定位到越界写发生的分配块"。 + # ============================================================ + def _det_probe(self): + if self._det_records is None: + return + free_flag: t.CUInt64T = t.CUInt64T(1) << 63 + i: t.CSizeT = 0 + while i < self._det_count: + p: t.CUInt64T = self._det_records[i * 2] + s: t.CUInt64T = self._det_records[i * 2 + 1] + if (s & free_flag) != 0: + # free 记录:跳过——buddy 分配器合并/重分配使 free 块内存不排他 + # (块合并进更大块后,新分配的用户区可覆盖旧记录的前标记区而旧块 + # 头仍为 0),前标记校验会误报(SlotsBugTest 1024B 块 hdr=0x0、 + # 前标记被 2048 合并分配数据写零的误报例,与 w0/w1 0xCD 校验同类)。 + # 只校验 active 记录(存活块独占,header LSB=1 不会合并, + # 前/后标记可靠)。 + i += 1 + continue + if s == 0: + i += 1 + continue # 无 size 记录(理论不发生,防御) + # active 记录:前标记(下溢检测)+ 后标记(上溢检测) + m_fa: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(p - 2, t.CPtr)) + mfv_a: t.CUInt16T = m_fa[0] + if mfv_a != t.CUInt16T(MEMBUDDY_DET_MARKER): + stdio.printf("[DET] 下溢写: ptr=%llu size=%llu 前标记=0x%04X(期望 0xCDCD)\n", + p, s, t.CUInt32T(mfv_a)) + stdlib.exit(1) + m16: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(p + s, t.CPtr)) + mv: t.CUInt16T = m16[0] + if mv != t.CUInt16T(MEMBUDDY_DET_MARKER): + stdio.printf("[DET] 越界写: ptr=%llu size=%llu 后标记=0x%04X(期望 0xCDCD)块内容前16B: ", + p, s, t.CUInt32T(mv)) + bi3: t.CInt = 0 + while bi3 < 16: + bv3: t.CUInt8T = (t.CUInt8T | t.CPtr)(t.CVoid(p + t.CUInt64T(bi3), t.CPtr))[0] + stdio.printf("%02X ", t.CUInt32T(bv3)) + bi3 += 1 + # 越界区(ptr+size 起 24 字节):0x00=被写穿 0xCD=未写 其它=写入值, + # 用于判断写入者写多长、往哪个方向 + stdio.printf("越界区: ") + bj3: t.CInt = 0 + while bj3 < 24: + bvj: t.CUInt8T = (t.CUInt8T | t.CPtr)(t.CVoid(p + s + t.CUInt64T(bj3), t.CPtr))[0] + stdio.printf("%02X ", t.CUInt32T(bvj)) + bj3 += 1 + # 记录表上下文:该条前 3 + 后 3 的 {ptr,size},推断越界块分配阶段 + stdio.printf("\n记录上下文: ") + ci2: t.CInt = -3 + while ci2 <= 3: + idx2: t.CSizeT = t.CSizeT(t.CInt(i) + ci2) + if idx2 < self._det_count: + cip: t.CUInt64T = self._det_records[idx2 * 2] + cis: t.CUInt64T = self._det_records[idx2 * 2 + 1] + stdio.printf("[%d]ptr=%llu sz=%llu ", ci2, cip, cis & (free_flag - 1)) + ci2 += 1 + # 重叠检测:同一 ptr 是否有多条记录(alloc 重叠实锤——不同 size + # 请求拿到同一块 → 互相覆盖;如 Token(72B) 与字符串 buf(7B) 共用块) + stdio.printf("\n同ptr记录: ") + ci3: t.CSizeT = 0 + while ci3 < self._det_count: + cp3: t.CUInt64T = self._det_records[ci3 * 2] + cs3: t.CUInt64T = self._det_records[ci3 * 2 + 1] + if cp3 == p and (cs3 & free_flag) == 0: + stdio.printf("[%zu]sz=%llu ", ci3, cs3 & (free_flag - 1)) + ci3 += 1 + stdio.printf("\n") + stdlib.exit(1) + i += 1 + # === Status Queries === @property @@ -778,14 +1024,14 @@ class MemBuddy(MemManager): # 返回 0=OK,非 0=损坏(rc 语义见调用方注释)。 # 用于 reset_to 前哨兵:把"崩溃点漂移"变成"确定性定位到损坏发生的文件"。 if self.chk_stack is None: - return + return 0 if from_mark > self.chk_depth: # from_mark 大于当前深度:调用方 mark 值异常(可能读错字段/跨实例), # 校验将 no-op → 越界写漏检。fail-fast 暴露。 stdio.printf( "[MEM] check_alive_blocks from_mark=%zu > chk_depth=%zu(mark 异常)\n", from_mark, self.chk_depth) - return + return 0 if from_mark >= self.chk_depth: return 0 if self.usable is None: diff --git a/posix.vp b/posix.vp index d98e7ac..3a0d7b5 100644 --- a/posix.vp +++ b/posix.vp @@ -162,57 +162,56 @@ class Dirent(): # ============================================================================= # File operations (10) # ============================================================================= -def open(path: t.CConst | str, oflag: INT, *args) -> INT | t.State: pass -def close(fd: INT) -> INT | t.State: pass -def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t | t.State: pass -def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t | t.State: pass -def lseek(fd: INT, offset: off_t, whence: INT) -> off_t | t.State: pass -def unlink(path: t.CConst | str) -> INT | t.State: pass -def access(path: t.CConst | str, amode: INT) -> INT | t.State: pass -def realpath(path: t.CConst | str, resolved: CHARPTR) -> CHARPTR | t.State: pass -def rename(oldpath: t.CConst | str, newpath: t.CConst | str) -> INT | t.State: pass -def chmod(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass - +extern def open(path: t.CConst | str, oflag: INT, *args) -> INT +extern def close(fd: INT) -> INT +extern def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t +extern def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t +extern def lseek(fd: INT, offset: off_t, whence: INT) -> off_t +extern def unlink(path: t.CConst | str) -> INT +extern def access(path: t.CConst | str, amode: INT) -> INT +extern def realpath(path: t.CConst | str, resolved: CHARPTR) -> CHARPTR +extern def rename(oldpath: t.CConst | str, newpath: t.CConst | str) -> INT +extern def chmod(path: t.CConst | str, mode: mode_t) -> INT # ============================================================================= # stat series (2) # ============================================================================= -def stat(path: t.CConst | str, buf: Stat | t.CPtr) -> INT | t.State: pass -def fstat(fd: INT, buf: Stat | t.CPtr) -> INT | t.State: pass +extern def stat(path: t.CConst | str, buf: Stat | t.CPtr) -> INT +extern def fstat(fd: INT, buf: Stat | t.CPtr) -> INT # ============================================================================= # Directory operations (6) # ============================================================================= -def opendir(name: t.CConst | str) -> DIR | t.CPtr | t.State: pass -def readdir(dirp: DIR | t.CPtr) -> Dirent | t.CPtr | t.State: pass -def closedir(dirp: DIR | t.CPtr) -> INT | t.State: pass -def mkdir(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass -def rmdir(path: t.CConst | str) -> INT | t.State: pass -def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR | t.State: pass -def chdir(path: t.CConst | str) -> INT | t.State: pass +extern def opendir(name: t.CConst | str) -> DIR | t.CPtr +extern def readdir(dirp: DIR | t.CPtr) -> Dirent | t.CPtr +extern def closedir(dirp: DIR | t.CPtr) -> INT +extern def mkdir(path: t.CConst | str, mode: mode_t) -> INT +extern def rmdir(path: t.CConst | str) -> INT +extern def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR +extern def chdir(path: t.CConst | str) -> INT # ============================================================================= # Process operations (8) # ============================================================================= -def fork() -> pid_t | t.State: pass -def execvp(file: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass -def execv(path: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass -def waitpid(pid: pid_t, status: INT | t.CPtr, options: INT) -> pid_t | t.State: pass -def pipe(fds: INT | t.CPtr) -> INT | t.State: pass -def dup2(oldfd: INT, newfd: INT) -> INT | t.State: pass -def _exit(status: INT) -> t.CVoid | t.State: pass -def getpid() -> pid_t | t.State: pass +extern def fork() -> pid_t +extern def execvp(file: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT +extern def execv(path: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT +extern def waitpid(pid: pid_t, status: INT | t.CPtr, options: INT) -> pid_t +extern def pipe(fds: INT | t.CPtr) -> INT +extern def dup2(oldfd: INT, newfd: INT) -> INT +extern def _exit(status: INT) -> t.CVoid +extern def getpid() -> pid_t # ============================================================================= # Environment operations (4) # ============================================================================= -def getenv(name: t.CConst | str) -> CHARPTR | t.State: pass -def setenv(name: t.CConst | str, value: t.CConst | str, overwrite: INT) -> INT | t.State: pass -def sysconf(name: INT) -> LONG | t.State: pass -def isatty(fd: INT) -> INT | t.State: pass +extern def getenv(name: t.CConst | str) -> CHARPTR +extern def setenv(name: t.CConst | str, value: t.CConst | str, overwrite: INT) -> INT +extern def sysconf(name: INT) -> LONG +extern def isatty(fd: INT) -> INT # ============================================================================= diff --git a/stdarg.vp b/stdarg.vp index 1d0192f..68586b3 100644 --- a/stdarg.vp +++ b/stdarg.vp @@ -1,9 +1,9 @@ import t -def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State: pass -def va_arg(args: t.CPtr, type: t.CPtr) -> t.CPtr | t.State: pass -def va_end(args: t.CPtr) -> t.State | t.State: pass +extern def va_start(args: t.CPtr, last_arg: t.CPtr) +extern def va_arg(args: t.CPtr, type: t.CPtr) -> t.CPtr +extern def va_end(args: t.CPtr) va_list: t.CTypedef = t.CUnsignedChar | t.CPtr -def arg(type: t.CType) -> t.State: pass \ No newline at end of file +extern def arg(type: t.CType) diff --git a/stdio.vp b/stdio.vp index 5dd3213..a74d249 100644 --- a/stdio.vp +++ b/stdio.vp @@ -1,11 +1,11 @@ import t, c -def printf(fmt: t.CConst | str, *args) -> int | t.State: pass -def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass -def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass -def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> int | t.State: pass -def puts(s: t.CConst | str) -> int | t.State: pass -def fputs(s: t.CConst | str, stream: bytes) -> int | t.State: pass -def fgets(buf: bytes, size: int, stream: bytes) -> bytes | t.State: pass -def fflush(stream: bytes) -> int | t.State: pass +extern def printf(fmt: t.CConst | str, *args) -> int +extern def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> int +extern def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> int +extern def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> int +extern def puts(s: t.CConst | str) -> int +extern def fputs(s: t.CConst | str, stream: bytes) -> int +extern def fgets(buf: bytes, size: int, stream: bytes) -> bytes +extern def fflush(stream: bytes) -> int diff --git a/stdlib.vp b/stdlib.vp index a580043..104b73d 100644 --- a/stdlib.vp +++ b/stdlib.vp @@ -2,9 +2,9 @@ from stdint import * import t -def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass -def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass -def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass -def free(p: t.CVoid | t.CPtr) -> t.State: pass -def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass -def exit(status: int) -> t.State: pass \ No newline at end of file +extern def malloc(size: t.CSizeT) -> t.CPtr +extern def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CPtr +extern def realloc(p: t.CPtr, size: t.CSizeT) -> t.CPtr +extern def free(p: t.CPtr) +extern def system(cmd: t.CConst | str) -> int +extern def exit(status: int) diff --git a/string.vp b/string.vp index 89981f1..fdaa966 100644 --- a/string.vp +++ b/string.vp @@ -73,7 +73,7 @@ def strlen(src: str) -> t.CSizeT | t.CExport: return length # String comparison function -def strcmp(str1: str, str2: str) -> t.CInt: +def strcmp(str1: str, str2: str) -> int: while str1[0] != '\0' and str2[0] != '\0': if str1[0] != str2[0]: return str1[0] - str2[0] @@ -86,7 +86,7 @@ def samestr(str1: str, str2: str) -> bool: # String compare function with limited length -def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: +def strncmp(str1: str, str2: str, n: t.CSizeT) -> int: i: t.CSizeT = 0 while str1[0] != '\0' and str2[0] != '\0' and i < n: if str1[0] != str2[0]: @@ -100,19 +100,19 @@ def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: # Memory compare function -def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> int: p1: BYTEPTR = BYTEPTR(ptr1) p2: BYTEPTR = BYTEPTR(ptr2) i: t.CSizeT = 0 while i < n: if p1[i] != p2[i]: - return t.CInt(p1[i]) - t.CInt(p2[i]) + return int(p1[i]) - int(p2[i]) i += 1 return 0 # String find function -def strchr(s: str, cr: t.CInt) -> str: +def strchr(s: str, cr: int) -> str: while s[0] != '\0': if s[0] == t.CChar(cr): return str(s) @@ -122,7 +122,7 @@ def strchr(s: str, cr: t.CInt) -> str: return None # String reverse find function (find last occurrence of character) -def strrchr(s: str, cr: t.CInt) -> str: +def strrchr(s: str, cr: int) -> str: last: str = None while s[0] != '\0': if s[0] == t.CChar(cr): @@ -164,7 +164,7 @@ def strspn(s: str, skip: str = " ") -> int: return si # Memory set function -def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: +def memset(ptr: t.CVoid | t.CPtr, value: int, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: # Original implementation: # p: BYTEPTR = BYTEPTR(ptr) # i: t.CSizeT @@ -248,9 +248,9 @@ def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.C return dest -def atoi(src: str) -> t.CInt: - num: t.CInt = 0 - sign: t.CInt = 1 +def atoi(src: str) -> int: + num: int = 0 + sign: int = 1 s: str = src if s == None: return 0 # 跳过空白 @@ -264,7 +264,7 @@ def atoi(src: str) -> t.CInt: s += 1 for ch in s: if ch < '0' or ch > '9': break - digit: t.CInt = ch - '0' + digit: int = ch - '0' num = num * 10 + digit return num * sign @@ -282,13 +282,13 @@ def atoll(src: str) -> t.CInt64T: elif s[0] == '+': s += 1 # 十六进制前缀 0x / 0X - is_hex: t.CInt = 0 + is_hex: int = 0 if s[0] == '0' and (s[1] == 'x' or s[1] == 'X'): is_hex = 1 s += 2 if is_hex: for ch in s: - d: t.CInt = 0 + d: int = 0 if ch >= '0' and ch <= '9': d = ch - '0' elif ch >= 'a' and ch <= 'f': @@ -302,7 +302,7 @@ def atoll(src: str) -> t.CInt64T: else: for ch in s: if ch < '0' or ch > '9': break - d: t.CInt = ch - '0' + d: int = ch - '0' digit: t.CInt64T = t.CInt64T(d) num = num * 10 + digit return num * sign @@ -325,7 +325,7 @@ def atof(src: str) -> t.CDouble: int_part: t.CDouble = 0.0 for ch in s: if ch < '0' or ch > '9': break - d1: t.CInt = ch - '0' + d1: int = ch - '0' int_part = int_part * 10.0 + t.CDouble(d1) s += 1 # 小数部分 @@ -335,13 +335,13 @@ def atof(src: str) -> t.CDouble: s += 1 for ch in s: if ch < '0' or ch > '9': break - d2: t.CInt = ch - '0' + d2: int = ch - '0' frac_div = frac_div * 10.0 frac_part = frac_part * 10.0 + t.CDouble(d2) s += 1 # 指数部分 - exp: t.CInt = 0 - exp_sign: t.CInt = 1 + exp: int = 0 + exp_sign: int = 1 if s[0] == 'e' or s[0] == 'E': s += 1 if s[0] == '-': @@ -351,7 +351,7 @@ def atof(src: str) -> t.CDouble: s += 1 for ch in s: if ch < '0' or ch > '9': break - d3: t.CInt = ch - '0' + d3: int = ch - '0' exp = exp * 10 + d3 s += 1 exp = exp * exp_sign @@ -368,7 +368,7 @@ def atof(src: str) -> t.CDouble: return result -def atof_out(src: str, out: t.CDouble | t.CPtr) -> t.CInt: +def atof_out(src: str, out: t.CDouble | t.CPtr) -> int: """atof 结果写入 out[0](输出参数方式,避免跨模块 double 返回值传递 bug) 返回值仅表示成功与否(1=成功,0=失败),结果值通过 out 指针传递, diff --git a/sys.vp b/sys.vp index 251a776..8f29169 100644 --- a/sys.vp +++ b/sys.vp @@ -20,12 +20,10 @@ _mbuddy: memhub.MemBuddy | t.CPtr # C Standard Library IO Declarations # ============================================================================= -def fgets(buf: bytes, size: int, stream: t.CVoid | t.CPtr) -> str | t.State: pass - -def fflush(stream: t.CVoid | t.CPtr) -> int | t.State: pass - +extern def fgets(buf: bytes, size: int, stream: t.CVoid | t.CPtr) -> str +extern def fflush(stream: t.CVoid | t.CPtr) -> int # C standard library exit (terminates the process after flushing the buffer, cross-platform) -def exit(status: int) -> t.State: pass +extern def exit(status: int) # =============================================================================