Files
TransPyC/includes/_withcontent.vp
T
TermiNexus 6759406a7e fix(_withcontent): _init_tls 加 _tls_index==0 守卫(TPV 未实现 @t.TLS 一次性语义)
TPV 编译器没有 @t.TLS 的首次执行守卫(TPC 有:全局标志+跳过块),
_init_tls 每次调用都重新 TlsAlloc → _get_stack 每次拿到新 TLS 索引和
新空栈 → push/find 各用各的栈,provider 永远匹配失败(Test 9 注入仍
FAIL 的根因)。_tls_index 初始为 0(TlsAlloc 成功不会返回 0),判重即
等价 TLS 语义。待办:TPV 函数翻译对齐 TPC HandlesFunctions.py L1763
实现 @t.TLS。
2026-08-15 06:36:53 +08:00

76 lines
2.7 KiB
Plaintext

import t, c
from stdint import *
from w32.win32process import TlsAlloc, TlsGetValue, TlsSetValue
import stdlib
import stdio
import string
# Maximum provider stack depth (compiler verifies sufficiency; increase if needed)
_MAX_PROVIDER_DEPTH: t.CDefine = 32
@t.Object
class _ProviderStack:
"""Provider stack, stores pairs of field names and pointers."""
names: t.CArray[VOIDPTR, 32]
ptrs: t.CArray[VOIDPTR, 32]
top: UINT64
# TLS index (global; all threads share the same index)
_tls_index: ULONG = 0
@t.TLS
def _init_tls():
"""Initialize TLS index (executes once; subsequent calls are skipped)."""
global _tls_index
# TPV 未实现 @t.TLS 的"首次执行"守卫(函数每次调用都执行体),
# 不加守卫会导致每次 _get_stack 都 TlsAlloc 新索引 → 每次拿到新
# 空栈 → push/find 各用各的栈,provider 永远匹配失败。_tls_index
# 初始为 0(TlsAlloc 成功不会返回 0),以此判重即等价 TLS 语义。
if _tls_index == 0:
_tls_index = TlsAlloc()
def _get_stack() -> _ProviderStack | t.CPtr:
"""Obtain current thread's provider stack. Allocate one if none exists."""
_init_tls()
stack: _ProviderStack | t.CPtr = TlsGetValue(_tls_index)
if stack == None:
stack = stdlib.malloc(_ProviderStack.__sizeof__())
string.memset(stack, 0, _ProviderStack.__sizeof__())
TlsSetValue(_tls_index, stack)
return stack
def _push_provider(field_name: str, ptr: t.CPtr):
"""Push a provider (field_name, ptr) onto the stack."""
stack: _ProviderStack | t.CPtr = _get_stack()
if stack.top >= _MAX_PROVIDER_DEPTH:
stdio.printf("[with] ERROR: provider stack overflow (depth=%lu, max=%d), field '%s' not injected\n", stack.top, _MAX_PROVIDER_DEPTH, field_name)
return
stack.names[stack.top] = field_name
stack.ptrs[stack.top] = ptr
stack.top = stack.top + 1
def _pop_provider():
"""Pop the top provider entry from the stack."""
stack: _ProviderStack | t.CPtr = _get_stack()
if stack.top > 0:
stack.top = stack.top - 1
def _find_provider(field_name: str) -> t.CPtr:
"""Search for matching field_name starting from stack top.
Return associated pointer, or NULL if no match found."""
stack: _ProviderStack | t.CPtr = _get_stack()
for i in range(stack.top - 1, -1, -1):
# 字段名用 strcmp 内容比较:编译器对每次 create_global_string 生成
# 独立的字符串常量(TPV 不去重),push/find 的指针地址不同,
# 指针 == 永假会导致 provider 匹配失败(__mbuddy__ 注入不上)。
if string.strcmp((str)(stack.names[i]), field_name) == 0:
return stack.ptrs[i]
return None