Skip to content

Commit 604fbbc

Browse files
committed
runtime: ByRef 零初始化 + 父缓存能力探测 + macOS weak_import(#268
ResolveRef 结果未初始化时 parent_id 是栈垃圾,GetByRef 越界 SIGSEGV。 嵌套 key 首次 ResolveRef 后 parent_id==0 则永久关闭父缓存(后端只写了叶子)。 Mach-O 用 weak_import + dynamic_lookup,避免旧 libkvspace 链接失败。
1 parent 7de7824 commit 604fbbc

3 files changed

Lines changed: 55 additions & 25 deletions

File tree

runtime/CMakeLists.txt

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,30 @@ set(KVSPACE_LIB_DIR "/usr/lib/kvspace" CACHE PATH "kvspace dispatch 前端安装
2121
target_link_directories(kvlang_runtime PRIVATE ${KVSPACE_LIB_DIR})
2222

2323
if(APPLE)
24-
# macOS:数学/线程符号在 libSystem 内(无 -lm/-lpthread);ld64 无 --disable-new-dtags
24+
# macOS:数学/线程符号在 libSystem 内(无 -lm/-lpthread);ld64 无 --disable-new-dtags。
25+
# weak_import 的 ResolveRef/GetByRef 在旧 libkvspace 上不存在,需 dynamic_lookup。
2526
target_link_libraries(kvlang_runtime PRIVATE kvspace)
2627
set_target_properties(kvlang_runtime PROPERTIES
27-
LINK_FLAGS "-Wl,-export_dynamic -Wl,-rpath,${KVSPACE_LIB_DIR}")
28+
LINK_FLAGS "-Wl,-export_dynamic -Wl,-rpath,${KVSPACE_LIB_DIR} -Wl,-undefined,dynamic_lookup")
2829
else()
2930
target_link_libraries(kvlang_runtime PRIVATE kvspace m pthread)
3031
# --export-dynamic 供 kvlang(term 扩展)找符号;--disable-new-dtags 使 rpath 转 DT_RPATH(传递)。
3132
set_target_properties(kvlang_runtime PROPERTIES
3233
LINK_FLAGS "-Wl,--export-dynamic -Wl,--disable-new-dtags -Wl,-rpath,${KVSPACE_LIB_DIR}")
3334
endif()
3435

35-
add_custom_command(
36-
OUTPUT "${BIN_DIR}/test_getmember_siblings"
37-
COMMAND ${CMAKE_C_COMPILER} -O2 -D_GNU_SOURCE
38-
-I${CMAKE_SOURCE_DIR}/include -I${CMAKE_SOURCE_DIR}/src
39-
${CMAKE_SOURCE_DIR}/tests/test_getmember_siblings.c
40-
-o ${BIN_DIR}/test_getmember_siblings
41-
-L${BIN_DIR}
42-
-Wl,--disable-new-dtags
43-
-Wl,-rpath,${BIN_DIR}
44-
-Wl,--no-as-needed -lkvspace -Wl,--as-needed -lkvlang_runtime
45-
DEPENDS kvlang_runtime "${CMAKE_SOURCE_DIR}/tests/test_getmember_siblings.c"
46-
VERBATIM)
47-
add_custom_target(test_getmember_siblings ALL DEPENDS "${BIN_DIR}/test_getmember_siblings")
36+
if(NOT APPLE)
37+
add_custom_command(
38+
OUTPUT "${BIN_DIR}/test_getmember_siblings"
39+
COMMAND ${CMAKE_C_COMPILER} -O2 -D_GNU_SOURCE
40+
-I${CMAKE_SOURCE_DIR}/include -I${CMAKE_SOURCE_DIR}/src
41+
${CMAKE_SOURCE_DIR}/tests/test_getmember_siblings.c
42+
-o ${BIN_DIR}/test_getmember_siblings
43+
-L${BIN_DIR} -L${KVSPACE_LIB_DIR}
44+
-Wl,--disable-new-dtags
45+
-Wl,-rpath,${BIN_DIR} -Wl,-rpath,${KVSPACE_LIB_DIR}
46+
-Wl,--no-as-needed -lkvspace -Wl,--as-needed -lkvlang_runtime
47+
DEPENDS kvlang_runtime "${CMAKE_SOURCE_DIR}/tests/test_getmember_siblings.c"
48+
VERBATIM)
49+
add_custom_target(test_getmember_siblings ALL DEPENDS "${BIN_DIR}/test_getmember_siblings")
50+
endif()

runtime/src/kvspace.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ static int ref_ok(kvlangKv_t *k) {
2525
return k->ref_on && kvspaceResolveRef && kvspaceGetByRef;
2626
}
2727

28+
static int parent_ok(kvlangKv_t *k) {
29+
return ref_ok(k) && k->parent_on;
30+
}
31+
2832
static kvlangRefEnt_t *pref_find(kvlangKv_t *k, const char *dir, size_t dl) {
2933
for (int i = 0; i < k->npref; i++) {
3034
const char *pk = k->pref[i].key;
@@ -150,7 +154,7 @@ static int dir_is_member(const char *dir, size_t dl) {
150154

151155
static void parent_put(kvlangKv_t *k, const char *dir, size_t dl, const kvspaceRef_t *rr) {
152156
kvlangRefEnt_t *e;
153-
if (!dir || !dl || !rr->parent_id || !rr->depth)
157+
if (!parent_ok(k) || !dir || !dl || !rr->parent_id || !rr->depth)
154158
return;
155159
if (dl >= 5 && memcmp(dir, "/lib/", 5) == 0)
156160
return;
@@ -211,6 +215,18 @@ static int last_dir_sep(const char *key, size_t *seplen) {
211215
return -1;
212216
}
213217

218+
/* Nested key + parent_id==0 → backend only wrote leaf fields; disable parent cache. */
219+
static void parent_note(kvlangKv_t *k, const char *key, const kvspaceRef_t *rr) {
220+
size_t seplen = 0;
221+
if (k->parent_probed || !key)
222+
return;
223+
if (last_dir_sep(key, &seplen) < 0)
224+
return;
225+
k->parent_probed = 1;
226+
if (!rr->parent_id)
227+
k->parent_on = 0;
228+
}
229+
214230
static int parent_prefix_ok(const kvlangRefEnt_t *e, const char *key) {
215231
size_t dl;
216232
const char *p;
@@ -316,6 +332,7 @@ kvlangKv_t *kvlangKvConnect(const char *dsn) {
316332
return NULL;
317333
}
318334
k->ref_on = 1;
335+
k->parent_on = 1;
319336
return k;
320337
}
321338

@@ -334,7 +351,7 @@ int kvlangKvGetOne(kvlangKv_t *k, const char *key, kvlangXvalue_t *out) {
334351
kvlangXvalueZero(out);
335352
uint8_t *d;
336353
uint32_t len;
337-
if (ref_ok(k) && k->npref && key) {
354+
if (parent_ok(k) && k->npref && key) {
338355
kvlangRefEnt_t *pe = (k->npref == 1)
339356
? (parent_prefix_ok(&k->pref[0], key) ? &k->pref[0] : NULL)
340357
: pref_cover(k, key);
@@ -383,7 +400,7 @@ int kvlangKvGetMember(kvlangKv_t *k, const char *dir, const char *name, kvlangXv
383400
memcpy(key, dir, dl);
384401
memcpy(key + dl, name, nl);
385402
key[dl + nl] = 0;
386-
if (ref_ok(k) && !hot_name_ok(name) && k->fpar.key &&
403+
if (parent_ok(k) && !hot_name_ok(name) && k->fpar.key &&
387404
memcmp(k->fpar.key, dir, k->fpar.klen) == 0 && dir[k->fpar.klen] == 0) {
388405
kvspaceRef_t r = { k->fpar.block_id, k->fpar.gen, 0, 0 };
389406
if (kvspaceGetByRef(k->h, &r, key, &d, &len) == 0 && d && len > 0) {
@@ -410,7 +427,7 @@ int kvlangKvGetMember(kvlangKv_t *k, const char *dir, const char *name, kvlangXv
410427
return 0;
411428
}
412429
}
413-
if (ref_ok(k)) {
430+
if (parent_ok(k)) {
414431
int hit = 0;
415432
if (nl >= MEMBER_SEP_LEN && memchr(name, 0xC2, nl)) {
416433
if (k->npref)
@@ -527,16 +544,17 @@ int kvlangKvSet(kvlangKv_t *k, const kvlangKvPair_t *pairs, int n, char *err, ui
527544
const char *slash = strrchr(key, '/');
528545
const char *rest = slash ? slash + 1 : key;
529546
int is_member = rest && memchr(rest, 0xC2, strlen(rest)) != NULL;
530-
if (is_member && (pref_cover(k, key) ||
547+
if (is_member && (!parent_ok(k) || pref_cover(k, key) ||
531548
(key[0] == '/' && strncmp(key, "/lib/", 5) == 0)))
532549
continue;
533-
kvspaceRef_t rr;
550+
kvspaceRef_t rr = {0};
534551
if (kvspaceResolveRef(k->h, key, &rr) == 0) {
552+
parent_note(k, key, &rr);
535553
if (!is_member) {
536554
ref_put(k, key, &rr);
537555
hot_put(k, rest, key, rr.block_id, rr.gen);
538556
}
539-
if (is_member || !k->fpar.key) {
557+
if (parent_ok(k) && (is_member || !k->fpar.key)) {
540558
size_t seplen = 0;
541559
int si = last_dir_sep(key, &seplen);
542560
if (si >= 0)

runtime/src/runtime_internal.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,28 @@ extern void kvspaceClose(void *h);
4343
extern int kvspaceGet(void *h, const char *key, int resolve, uint8_t **out,
4444
uint32_t *out_len);
4545

46+
/* 对齐 kvspace/include/kvspace/kvspace.h。parent_id/depth 由 ResolveRef 填;
47+
* 后端只写前 8 字节时 parent_id 保持 0,runtime 永久关闭父缓存。 */
4648
typedef struct {
4749
uint32_t block_id;
4850
uint32_t gen;
4951
uint32_t parent_id;
5052
uint32_t depth;
5153
} kvspaceRef_t;
54+
#if defined(__APPLE__)
55+
#define KVLANG_KVSPACE_WEAK __attribute__((weak_import))
56+
#else
57+
#define KVLANG_KVSPACE_WEAK __attribute__((weak))
58+
#endif
5259
extern int kvspaceResolveRef(void *h, const char *key, kvspaceRef_t *ref)
53-
__attribute__((weak));
60+
KVLANG_KVSPACE_WEAK;
5461
extern int kvspaceGetByRef(void *h, kvspaceRef_t *ref, const char *key_fallback,
5562
uint8_t **out, uint32_t *out_len)
56-
__attribute__((weak));
63+
KVLANG_KVSPACE_WEAK;
5764
extern int kvspaceSetPartByRef(void *h, kvspaceRef_t *ref,
5865
const char *key_fallback, uint32_t offset,
5966
const uint8_t *buf, uint32_t buf_len, char *err,
60-
uint32_t err_cap) __attribute__((weak));
67+
uint32_t err_cap) KVLANG_KVSPACE_WEAK;
6168
/* 指令边界回收读借用池;定位读/写(分片);只读 head 前缀。见 kvspace.h 契约。 */
6269
extern void kvspaceReadReset(void *h);
6370
extern int kvspaceGetPart(void *h, const char *key, uint32_t offset,
@@ -154,6 +161,8 @@ typedef struct {
154161
kvlangRefEnt_t ref[KVLANG_REF_CAP];
155162
int nref;
156163
int ref_on;
164+
int parent_on; /* 嵌套 ResolveRef 后 parent_id==0 则永久关闭 */
165+
int parent_probed;
157166
kvlangRefEnt_t pref[KVLANG_PREF_CAP]; /* · map ART parents */
158167
int npref;
159168
int pref_i;

0 commit comments

Comments
 (0)