更新,可自举

This commit is contained in:
TermiNexus committed 2026-08-27 10:16:28 +08:00
1 parent d6d06b2f1a
commit f087aa88e2
22 files changed
+459 -133

No files matched your search

+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -1,5 +1,5 @@
import t, c
import string
import t, c
# ==============================================
+14 -14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+8 -1
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
# ============================================================
+256 -10
View File
@@ -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:
+31 -32
View File
@@ -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
# =============================================================================
+4 -4
View File
@@ -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)
+8 -8
View File
@@ -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
+6 -6
View File
@@ -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)
+20 -20
View File
@@ -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 指针传递,
+3 -5
View File
@@ -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)
# =============================================================================