You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

强制宏参数为字符串字面量:漏洞排查与优化方案

字符串字面量宏的边缘情况与改进方案

原宏#define SV(str) (sizeof(str) - 1)在传入非字符串字面量(如普通char指针)时,编译正常但结果完全错误。改成#define SV(str) (sizeof("" str "") - 1)后,虽能对非字面量参数触发编译错误,但仍存在以下漏洞:

1. 多参数/带逗号参数的陷阱

如果传入带逗号的参数(比如SV("a", "b")),宏展开后会变成sizeof("" "a", "b" "") - 1。由于逗号运算符优先级最低,sizeof实际计算的是最后一个表达式"b" ""的长度,结果为2-1=1,完全不符合预期,且编译不会报错。

2. 复合字面量的绕过

若传入复合字面量(如SV((char[]){"hello"})),虽然它是数组类型能通过字符串拼接检查,但复合字面量是可变的,违反了原约束中“不可变”的要求,且宏无法识别这种情况。

3. 宽字符串不兼容

如果传入宽字符串字面量(如SV(L"hello")),窄字符串与宽字符串的拼接会直接触发编译错误,若宏需要支持宽字符串,当前写法无法适配。

改进后的宏实现

结合预处理参数检查、静态断言和类型匹配,可写出更严格的宏,同时兼容标准C:

// 计算宏参数个数,用于检查是否传入单一参数
#define _SV_NUM_ARGS(...) _SV_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1,0)
#define _SV_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N

// 判断参数是否为const字符串字面量(匹配不可变、数组类型的约束)
#define _SV_IS_STRING_LITERAL(str) _Generic((str), \
    const char[sizeof(str)]: 1, \
    default: 0)

#define SV(str) \
    _Static_assert(_SV_NUM_ARGS(str) == 1, "SV requires exactly one string literal argument"), \
    _Static_assert(_SV_IS_STRING_LITERAL(str), "Argument must be a const string literal"), \
    (sizeof(str) - 1)

改进点说明

  1. 参数个数检查:通过_SV_NUM_ARGS确保只能传入单一参数,避免逗号运算符导致的错误。
  2. 类型断言:利用_Generic匹配const char[N]类型(字符串字面量的真实类型),排除普通指针、非const复合字面量等不符合约束的输入。
  3. 直接使用原sizeof逻辑:在通过所有检查后,回到sizeof(str)-1的计算,避免字符串拼接带来的额外问题。

如果需要支持宽字符串,可以新增针对宽字符的宏:

#define _SV_IS_WIDE_STRING_LITERAL(str) _Generic((str), \
    const wchar_t[sizeof(str)]: 1, \
    default: 0)

#define SV_W(str) \
    _Static_assert(_SV_NUM_ARGS(str) == 1, "SV_W requires exactly one wide string literal argument"), \
    _Static_assert(_SV_IS_WIDE_STRING_LITERAL(str), "Argument must be a const wide string literal"), \
    (sizeof(str)/sizeof(wchar_t) - 1)

内容的提问来源于stack exchange,提问作者Madagascar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:55:57