From 04129949532ec2c1642db498503a9d2abe6b56ff Mon Sep 17 00:00:00 2001 From: AskaEth Date: Thu, 5 Nov 2026 20:19:55 +0800 Subject: [PATCH] =?UTF-8?q?test(sdk):=20time64=E2=86=92o32=20time32=20?= =?UTF-8?q?=E6=8D=A2=E7=AE=97=E5=AE=BF=E4=B8=BB=E5=8D=95=E6=B5=8B=EF=BC=88?= =?UTF-8?q?23=20=E9=A1=B9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_meow_time64.c 覆盖 meow_ui_time.c 接管入口共用的纯换算层: - 相对超时(futex):普通值、亚秒、INT32_MAX 上界、上/下溢饱和、负值透传; - 绝对时刻(clock_settime/timerfd):int32 上下界接受、越界拒绝(对应 ENOTSUP); - itimerspec 四字段不串位、任一越界整体失败且不写坏输出、反向展开对称; - 结构宽度 before/after:同一块 16B time64 内存按内核 o32 只读 8B 时, 0.4s 被读成 {0,0}(立即超时)、2.3s 被读成 2s 整;经本层转换后内核读到 {2, 300000000}。 宿主编译/运行: gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/m.o gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time64.c /tmp/m.o -o test_meow_time64 ./test_meow_time64 # == PASS == M11 的 test_meow_time.c 仍 PASS(回归)。 --- patch_v2/sdk/test_meow_time64.c | 170 ++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 patch_v2/sdk/test_meow_time64.c diff --git a/patch_v2/sdk/test_meow_time64.c b/patch_v2/sdk/test_meow_time64.c new file mode 100644 index 0000000..151de83 --- /dev/null +++ b/patch_v2/sdk/test_meow_time64.c @@ -0,0 +1,170 @@ +/* test_meow_time64.c — 宿主单测:time64 → 内核 o32 time32 的换算与结构宽度。 + * + * 背景(M16):zig clang 给 32 位 mips 预定义 __ILP32__,打穿 musl 的 time64 回退守卫, + * futex 相对超时 / timerfd / clock_settime 等入口把 16 字节(time64)结构直接交给 time32 + * 系统调用。meow_ui_time.c 的接管入口统一经 meow_ui_internal.h 里这几个纯换算函数转换, + * 本测试在宿主上把「换算结果 + 内核实际读到的宽度」固定住,不需要 mips 设备。 + * + * 编译(patch_v2/sdk 目录下): + * gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/meow_ui_time.o + * gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time64.c /tmp/meow_ui_time.o \ + * -o test_meow_time64 + * 运行:./test_meow_time64 (exit 0=PASS / 1=FAIL) + */ +#include +#include +#include +#include +#include + +#include "meow_ui.h" +#include "meow_ui_internal.h" + +static int g_fail = 0; + +static void check(const char *name, int ok) +{ + if (ok) { + printf("ok %s\n", name); + } else { + printf("FAIL %s\n", name); + g_fail = 1; + } +} + +static void check_time32(const char *name, const struct meow_time32 *got, + int32_t sec, int32_t nsec) +{ + if (got->tv_sec == sec && got->tv_nsec == nsec) { + printf("ok %s = {%d, %d}\n", name, (int)got->tv_sec, (int)got->tv_nsec); + } else { + printf("FAIL %s = {%d, %d},期望 {%d, %d}\n", name, + (int)got->tv_sec, (int)got->tv_nsec, (int)sec, (int)nsec); + g_fail = 1; + } +} + +/* 模拟 o32 内核对「调用者给的指针」的实际读法:只读前 8 字节,按两个 int32 解释。 */ +static void kernel_time32_view(const void *ptr, struct meow_time32 *out) +{ + memcpy(out, ptr, sizeof *out); +} + +static void test_rel(void) +{ + struct meow_time32 t; + + meow_time32_rel_from_parts(5, 123456789, &t); + check_time32("rel 普通值", &t, 5, 123456789); + + meow_time32_rel_from_parts(0, 500000000, &t); + check_time32("rel 亚秒(原缺陷会变 {0,0})", &t, 0, 500000000); + + meow_time32_rel_from_parts(INT32_MAX, 999999999, &t); + check_time32("rel int32 上界", &t, INT32_MAX, 999999999); + + meow_time32_rel_from_parts((int64_t)INT32_MAX + 1, 1, &t); + check_time32("rel 上溢饱和到 INT32_MAX", &t, INT32_MAX, 1); + + meow_time32_rel_from_parts(INT64_MAX, 0, &t); + check_time32("rel INT64_MAX 饱和", &t, INT32_MAX, 0); + + meow_time32_rel_from_parts(-1, 500000000, &t); + check_time32("rel 负值透传(调用方另判 ETIMEDOUT)", &t, -1, 500000000); + + meow_time32_rel_from_parts((int64_t)INT32_MIN - 1, 0, &t); + check_time32("rel 下溢饱和到 INT32_MIN", &t, INT32_MIN, 0); +} + +static void test_abs(void) +{ + struct meow_time32 t; + + t.tv_sec = 7; + t.tv_nsec = 7; + check("abs 普通值", meow_time32_abs_from_parts(1700000000, 250000000, &t) == 0); + check_time32("abs 普通值内容", &t, 1700000000, 250000000); + + check("abs int32 上界接受", meow_time32_abs_from_parts(INT32_MAX, 0, &t) == 0); + check("abs int32+1 拒绝", meow_time32_abs_from_parts((int64_t)INT32_MAX + 1, 0, &t) == -1); + check("abs int32 下界接受", meow_time32_abs_from_parts(INT32_MIN, 0, &t) == 0); + check("abs int32-1 拒绝", meow_time32_abs_from_parts((int64_t)INT32_MIN - 1, 0, &t) == -1); + check("abs 2038 后一秒拒绝", meow_time32_abs_from_parts(2147483648LL, 0, &t) == -1); +} + +static void test_itimerspec(void) +{ + struct meow_time64_itimerspec in; + struct meow_itimerspec32 out, back32; + struct meow_time64_itimerspec back; + + in.it_interval.tv_sec = 1; + in.it_interval.tv_nsec = 250000000; + in.it_value.tv_sec = 3600; + in.it_value.tv_nsec = 999999999; + memset(&out, 0xAA, sizeof out); + check("itimerspec 四字段转换成功", + meow_time32_itimerspec_from_64(&in, &out) == 0); + check_time32("itimerspec interval", &out.it_interval, 1, 250000000); + check_time32("itimerspec value", &out.it_value, 3600, 999999999); + + /* 越界必须整体失败且不改 *out(timerfd_settime 回 ENOTSUP 的前提) */ + memcpy(&back32, &out, sizeof back32); + in.it_value.tv_sec = (int64_t)INT32_MAX + 1; + check("itimerspec 越界拒绝", meow_time32_itimerspec_from_64(&in, &out) == -1); + check("itimerspec 越界不写坏输出", memcmp(&back32, &out, sizeof out) == 0); + + /* 反向(timerfd_gettime)字段不串位 */ + memset(&back, 0, sizeof back); + meow_time64_itimerspec_from_32(&back32, &back); + check("itimerspec 反向 sec/nsec 不串位", + back.it_interval.tv_sec == 1 && back.it_interval.tv_nsec == 250000000 && + back.it_value.tv_sec == 3600 && back.it_value.tv_nsec == 999999999); +} + +/* 结构宽度证明:同一块内存按「libc 头 ABI」与「内核 o32 ABI」读出的值不同。 */ +static void test_struct_width(void) +{ + struct timespec ts; + + if (sizeof(time_t) != 8 || offsetof(struct timespec, tv_nsec) != 8) { + printf("skip 结构宽度模拟(宿主 time_t/timespec 布局与 ILP32+time64 不一致)\n"); + return; + } + + /* 剩 0.4s:16 字节 time64 结构的前 8 字节被内核读成 {sec=0, nsec=0} → 立即超时 */ + memset(&ts, 0, sizeof ts); + ts.tv_sec = 0; + ts.tv_nsec = 400000000; + struct meow_time32 old_view; + kernel_time32_view(&ts, &old_view); + check("旧 ABI:0.4s 被内核读成 {0,0}(立即超时)", + old_view.tv_sec == 0 && old_view.tv_nsec == 0); + + /* 剩 2.3s:旧 ABI 丢掉 0.3s,只剩 2s 整 */ + memset(&ts, 0, sizeof ts); + ts.tv_sec = 2; + ts.tv_nsec = 300000000; + kernel_time32_view(&ts, &old_view); + check("旧 ABI:2.3s 被内核读成 2s 整", + old_view.tv_sec == 2 && old_view.tv_nsec == 0); + + /* 新路径:先转换再交给内核,宽度与值都对 */ + struct meow_time32 fixed; + meow_time32_rel_from_parts((int64_t)ts.tv_sec, (int64_t)ts.tv_nsec, &fixed); + struct meow_time32 new_view; + kernel_time32_view(&fixed, &new_view); + check("新 ABI:内核读到 {2, 300000000}", new_view.tv_sec == 2 && + new_view.tv_nsec == 300000000); +} + +int main(void) +{ + test_rel(); + test_abs(); + test_itimerspec(); + test_struct_width(); + + printf(g_fail ? "== FAIL ==\n" : "== PASS ==\n"); + return g_fail; +}