如何临时覆盖malloc以测试s21_create_matrix内存分配失败场景
解决C语言测试中临时替换malloc函数的方案
你直接尝试malloc = mock_malloc的写法是行不通的——malloc是标准库的函数标识符,并非可修改的函数指针变量,C语言不允许直接赋值替换。下面提供三种可行的方案来测试s21_create_matrix中malloc返回NULL的场景:
方案1:预处理宏替换(最简单的单元测试方案)
通过预编译宏将所有malloc调用替换为你的mock函数,编译测试用例时启用该宏即可。
测试代码修改
#include <stdlib.h> #include "s21_matrix.h" #include <check.h> // 保存原始malloc指针(可选,若需要在mock中调用真实malloc时使用) static void *(*original_malloc)(size_t) = malloc; // 模拟malloc返回NULL的mock函数 void *mock_malloc(size_t size) { (void)size; return NULL; } START_TEST(create_matrix_malloc_failure) { matrix_t matrix; int status = s21_create_matrix(3, 4, &matrix); ck_assert_int_eq(status, S21_INCORRECT_MATRIX); ck_assert_int_eq(0, matrix.rows); ck_assert_int_eq(0, matrix.columns); ck_assert_ptr_null(matrix.matrix); } END_TEST // 测试套件设置 Suite *s21_matrix_suite(void) { Suite *s = suite_create("s21_matrix"); TCase *tc_core = tcase_create("core"); tcase_add_test(tc_core, create_matrix_malloc_failure); suite_add_tcase(s, tc_core); return s; } int main(void) { int number_failed; Suite *s = s21_matrix_suite(); SRunner *sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }
编译命令
编译时添加宏定义,将所有malloc替换为mock_malloc:
gcc -o test_matrix test_matrix.c s21_matrix.c -lcheck -Dmalloc=mock_malloc
方案2:动态库符号替换(适合不修改编译参数的场景)
在Linux/macOS下,利用动态链接器的预加载机制,替换标准库的malloc函数。
1. 编写mock动态库
#include <stdlib.h> #include <dlfcn.h> // 保存真实malloc的地址 static void *(*real_malloc)(size_t) = NULL; // 库加载时初始化,获取真实malloc的地址 __attribute__((constructor)) void init_mock(void) { real_malloc = dlsym(RTLD_NEXT, "malloc"); } // 自定义malloc,返回NULL模拟分配失败 void *malloc(size_t size) { (void)size; return NULL; }
2. 编译动态库
gcc -shared -fPIC -o libmockmalloc.so mock_malloc.c -ldl
3. 运行测试时预加载库
LD_PRELOAD=./libmockmalloc.so ./test_matrix
方案3:代码重构(最可控的长期维护方案)
对生产代码进行微小重构,将malloc封装为自定义函数,测试时直接替换该函数。
1. 修改生产代码
在矩阵模块中封装内存分配函数:
// s21_matrix.h中声明 void *s21_malloc(size_t size); // s21_matrix.c中实现 #include <stdlib.h> #include "s21_matrix.h" void *s21_malloc(size_t size) { return malloc(size); // 默认调用标准malloc } // 修改s21_create_matrix中的malloc为s21_malloc int s21_create_matrix(int rows, int columns, matrix_t *result) { int status = S21_OK; if (result == NULL || rows < 0 || columns < 0) { result->rows = 0; result->columns = 0; result->matrix = NULL; return S21_INCORRECT_MATRIX; } if (status == S21_OK) { result->matrix = (double **)s21_malloc(sizeof(double *) * rows); if (result->matrix == NULL) { result->rows = 0; result->columns = 0; result->matrix = NULL; status = S21_INCORRECT_MATRIX; } } for (int i = 0; i < rows && status == S21_OK; ++i) { result->matrix[i] = (double *)s21_malloc(sizeof(double) * columns); if (result->matrix[i] == NULL) { status = S21_INCORRECT_MATRIX; for (int j = 0; j < i; ++j) { free(result->matrix[j]); } free(result->matrix); } } if (status == S21_OK) { result->columns = columns; result->rows = rows; } return status; }
2. 测试代码中替换自定义分配函数
#include <stdlib.h> #include "s21_matrix.h" #include <check.h> // 保存原始s21_malloc的指针 static void *(*original_s21_malloc)(size_t) = s21_malloc; void *mock_malloc(size_t size) { (void)size; return NULL; } START_TEST(create_matrix_malloc_failure) { // 替换自定义分配函数 s21_malloc = mock_malloc; matrix_t matrix; int status = s21_create_matrix(3, 4, &matrix); // 恢复原始函数 s21_malloc = original_s21_malloc; ck_assert_int_eq(status, S21_INCORRECT_MATRIX); ck_assert_int_eq(0, matrix.rows); ck_assert_int_eq(0, matrix.columns); ck_assert_ptr_null(matrix.matrix); } END_TEST
注意事项
- 宏替换方案需确保所有
malloc调用都被覆盖,包括依赖库中的调用 - 动态库替换仅对动态链接的程序有效,静态链接程序无法使用
- 代码重构方案对生产代码侵入极小,且便于扩展其他内存分配测试场景
内容的提问来源于stack exchange,提问作者house
相关产品推荐
相关产品推荐

