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

如何临时覆盖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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 04:50:17