背景
JSON 字符串值里的 NUL(码点 U+0000,JSON 源文本中写作反斜杠 + u0000)在往返后被截断,其后内容全部丢失。
实测(下文用 <NUL> 表示该码点):
[DIFF] nul-byte in: {"v":"before<NUL>after"} out: {"v":"before"}
成因:json.go 的 constructTLV 对 char/* kind 走 kvspaceNewChar(kind, const char *s, ...)——参数是 C 字符串,遇 NUL 终止。函数内部把 raw 追加一个终止符再传入,NUL 之后的字节到不了 kvspace。
同组其余 12 例全部无损:CJK、emoji(含 ZWJ 序列 👨👩👧👦)、代理对、RTL、制表/换行/回车/引号/反斜杠转义、U+0001 与 U+001F 等控制字符、10KB 长串、值中出现 · 与 ‥、值中嵌 JSON 文本。所以问题只出在 NUL 这一个码点上,是 ABI 用法问题而非编码问题——U+0001 能过而 U+0000 不能,正说明卡点是 C 字符串终止符而非字符集。
需求描述
字符串值应可承载任意字节序列,包括 NUL。方案文档 §5.4 已明确「字符串值(value)不受 key 字符约束,任意字符皆可」。
预期结果
含 U+0000 的字符串值无损往返;长度与字节内容逐字节相等。
方案简述
不需要 kvspace 改动——dispatch ABI 已导出带显式长度的入口:
// kvspace-durable/src/ffi.rs:497
pub extern "C" fn kvspaceNewCharByte(bytes: *const u8, len: u32,
out: *mut *mut u8, out_len: *mut u32) -> c_int
nm -D /usr/lib/libkvspace.so 确认 kvspaceNewCharByte 在导出符号表中。constructTLV 的 char/* 分支改调它(传 raw 指针与 len(raw),不再追加终止符)即可。
需确认 NewCharByte 落盘的 kind 与 dims 约定和 NewChar 一致(char/utf8、一维、dims=[字节数]),否则会与既有落盘不兼容;同时确认 kvspace-c(shm)侧同名符号行为一致。
背景
JSON 字符串值里的 NUL(码点 U+0000,JSON 源文本中写作反斜杠 +
u0000)在往返后被截断,其后内容全部丢失。实测(下文用
<NUL>表示该码点):成因:
json.go的constructTLV对char/*kind 走kvspaceNewChar(kind, const char *s, ...)——参数是 C 字符串,遇 NUL 终止。函数内部把 raw 追加一个终止符再传入,NUL 之后的字节到不了 kvspace。同组其余 12 例全部无损:CJK、emoji(含 ZWJ 序列
👨👩👧👦)、代理对、RTL、制表/换行/回车/引号/反斜杠转义、U+0001 与 U+001F 等控制字符、10KB 长串、值中出现·与‥、值中嵌 JSON 文本。所以问题只出在 NUL 这一个码点上,是 ABI 用法问题而非编码问题——U+0001 能过而 U+0000 不能,正说明卡点是 C 字符串终止符而非字符集。需求描述
字符串值应可承载任意字节序列,包括 NUL。方案文档 §5.4 已明确「字符串值(value)不受 key 字符约束,任意字符皆可」。
预期结果
含 U+0000 的字符串值无损往返;长度与字节内容逐字节相等。
方案简述
不需要 kvspace 改动——dispatch ABI 已导出带显式长度的入口:
nm -D /usr/lib/libkvspace.so确认kvspaceNewCharByte在导出符号表中。constructTLV的char/*分支改调它(传 raw 指针与len(raw),不再追加终止符)即可。需确认
NewCharByte落盘的 kind 与 dims 约定和NewChar一致(char/utf8、一维、dims=[字节数]),否则会与既有落盘不兼容;同时确认 kvspace-c(shm)侧同名符号行为一致。