更新,可自举
This commit is contained in:
1 parent
d6d06b2f1a
commit
f087aa88e2
22 files changed
+459
-133
No files matched your search
@@ -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.
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
-1
@@ -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
|
||||
)
|
||||
|
||||
|
||||
|
||||
+12
@@ -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
|
||||
+2
-2
@@ -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,
|
||||
|
||||
+4
-4
@@ -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):
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import t, c
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
|
||||
+14
-14
@@ -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
|
||||
|
||||
+10
-10
@@ -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)
|
||||
|
||||
+8
-8
@@ -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)
|
||||
|
||||
+17
-1
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
+30
-3
@@ -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'
|
||||
dst[dlen + i] = '\0'
|
||||
_g_last_pos = dlen + i
|
||||
@@ -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))
|
||||
|
||||
+17
-1
@@ -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
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
@@ -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
|
||||
extern def arg(type: t.CType)
|
||||
@@ -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
|
||||
@@ -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
|
||||
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)
|
||||
@@ -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 指针传递,
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
Reference in new issue
Block a user