Criterion框架字符串参数化测试崩溃问题及原因咨询
咱们先拆解你遇到的问题:同样是参数化测试,int类型能正常跑,字符串版本却直接崩溃,后来用cr_malloc复制字面量就好了——核心原因其实是字符串字面量的存储特性和Criterion框架的内存管理逻辑不匹配。
一、第一个测试崩溃的根本原因
你最初的代码里,这段定义的字符串指针数组存在关键问题:
// 这里的指针指向只读段的字符串字面量 static char* strings[] = {"Foo", "Bar"}; return cr_make_param_array(char*, strings, strings_count);
"Foo"、"Bar"属于字符串字面量,这类数据在程序编译时就被放到了只读数据段(.rodata)里,这块内存是受系统保护的,既不能修改,也不能用free(或者Criterion的cr_free)去释放。
而Criterion的参数化测试框架,对于指针类型的参数(比如你这里的char*),会默认在每个测试用例执行完毕后,尝试用cr_free去释放参数指向的内存。当框架尝试释放只读段的内存时,就会触发非法内存访问,直接导致程序崩溃——这就是你看到CRASH!的原因。
二、为什么int参数的测试能正常运行?
你的int测试用的是:
static int numbers[] = {1, 2}; return cr_make_param_array(int, numbers, numbers_count);
这里的数组属于静态数据段,而且参数类型是基本类型int。Criterion对基本类型的参数化处理逻辑和指针类型不同:它会直接复制数组里的整数值(或者传递指向静态数组元素的指针,但不会尝试释放静态内存),不需要涉及内存释放操作,所以不会触发错误。
三、你后来的修复方案为什么有效?
你改用cr_malloc在堆上分配字符串内存,再把字面量复制过去:
strings[k] = cr_malloc(strlen(STRINGS[k]) + 1); strcpy(strings[k], STRINGS[k]);
这时候指针指向的是框架可以管理的堆内存。因为cr_malloc是Criterion配套的内存分配函数,框架会用对应的cr_free来释放这块内存,整个流程符合框架的内存管理规则,所以测试就能正常执行,不会崩溃。
对你疑问的解答
你的假设不完全准确:字符串字面量并不是动态分配的,它们是编译时就确定的静态只读内存。崩溃的原因不是字面量的分配方式,而是框架尝试释放了不属于它管理的只读内存区域。
总结要点
- 当用Criterion做指针类型的参数化测试时,参数指向的内存必须用
cr_malloc/cr_calloc/cr_realloc分配,确保框架能正确管理内存的分配与释放 - 字符串字面量不能直接作为指针参数使用,因为它们在只读段,无法被框架安全释放
- 基本类型(int、float等)的参数不需要考虑这个问题,框架会直接处理值的复制,不涉及内存释放操作
备注:内容来源于stack exchange,提问作者Mehdi Charife

