如果 return 值结构有太多成员,则包装函数指针参数会更改
Wrapped function pointer parameter changes if return value struct has too many members
我用 gcc main.c -Wl,--wrap=foo -lcmocka
编译以下 main.c
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
typedef struct ExampleStruct {
int32_t foo;
int32_t qux;
void* bar;
} ExampleStruct;
ExampleStruct __wrap_foo(int32_t foo, int32_t qux, void* bar) {
printf("bar after: %p\n", bar);
return (ExampleStruct) {
.foo = foo,
.qux = qux,
.bar = bar
};
}
void test() {
void* bar = "fef";
printf("bar before: %p\n", bar);
foo(1, 1, bar);
assert_int_equal(2,2);
}
int main() {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test),
};
return cmocka_run_group_tests_name("success_test", tests, NULL, NULL);
}
我得到以下输出:
[==========] Running 1 test(s).
[ RUN ] test
bar before: 0x40087f
bar after: 0x40087f
[ OK ] test
[==========] 1 test(s) run.
[ PASSED ] 1 test(s).
但是如果我添加一个新成员 baz
到 ExampleStruct
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
typedef struct ExampleStruct {
int32_t foo;
int32_t qux;
int32_t baz;
void* bar;
} ExampleStruct;
ExampleStruct __wrap_foo(int32_t foo, int32_t qux, int32_t baz, void* bar) {
printf("bar after: %p\n", bar);
return (ExampleStruct) {
.foo = foo,
.qux = qux,
.baz = baz,
.bar = bar
};
}
void test() {
void* bar = "fef";
printf("bar before: %p\n", bar);
foo(1, 1, 1, bar);
assert_int_equal(2,2);
}
int main() {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test),
};
return cmocka_run_group_tests_name("success_test", tests, NULL, NULL);
}
我得到以下输出:
[==========] Running 1 test(s).
[ RUN ] test
bar before: 0x40086f
bar after: 0x7f3ff17cb2cd
[ ERROR ] --- Test failed with exception: Segmentation fault(11)
[ FAILED ] test
[==========] 1 test(s) run.
[ PASSED ] 0 test(s).
[ FAILED ] 1 test(s), listed below:
[ FAILED ] test
如果我不使用包装函数,一切似乎都按预期工作。
更多详情
我是 运行 gcc 4.8.5
GNU ld 版本 2.27-44
问题
为什么向 ExampleStruct
添加另一个成员会导致分段错误?为什么 bar
在复制到 __wrap_foo
的参数时会改变值?
您需要添加 foo
函数的声明。当前 foo(1, 1, 1, bar);
将使用 int foo()
的隐式声明。自 C99 以来,隐式声明无效,因此您应该能够打开更多警告来捕获此问题 (-Wimplicit-function-declaration -Werror
)。
隐式声明的函数接受你给它的参数(这实际上匹配 __wrap_foo
,假设 int32_t
是 typedef
对 int
)和将 return int
,而不是 ExampleStruct
,因此您的程序将具有 未定义的行为。
示例:
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
typedef struct ExampleStruct {
int32_t foo;
int32_t qux;
int32_t baz;
void* bar;
} ExampleStruct;
// ** add this declaration **
ExampleStruct foo(int32_t foo, int32_t qux, int32_t baz, void* bar);
ExampleStruct __wrap_foo(int32_t foo, int32_t qux, int32_t baz, void* bar) {
printf("bar after : %p\n", bar);
return (ExampleStruct) {
.foo = foo,
.qux = qux,
.baz = baz,
.bar = bar
};
}
int main() {
void* bar = "fef";
printf("bar before: %p\n", bar);
foo(1, 1, 1, bar);
assert(2 == 2);
}
我用 gcc main.c -Wl,--wrap=foo -lcmocka
编译以下 main.c
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
typedef struct ExampleStruct {
int32_t foo;
int32_t qux;
void* bar;
} ExampleStruct;
ExampleStruct __wrap_foo(int32_t foo, int32_t qux, void* bar) {
printf("bar after: %p\n", bar);
return (ExampleStruct) {
.foo = foo,
.qux = qux,
.bar = bar
};
}
void test() {
void* bar = "fef";
printf("bar before: %p\n", bar);
foo(1, 1, bar);
assert_int_equal(2,2);
}
int main() {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test),
};
return cmocka_run_group_tests_name("success_test", tests, NULL, NULL);
}
我得到以下输出:
[==========] Running 1 test(s).
[ RUN ] test
bar before: 0x40087f
bar after: 0x40087f
[ OK ] test
[==========] 1 test(s) run.
[ PASSED ] 1 test(s).
但是如果我添加一个新成员 baz
到 ExampleStruct
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
typedef struct ExampleStruct {
int32_t foo;
int32_t qux;
int32_t baz;
void* bar;
} ExampleStruct;
ExampleStruct __wrap_foo(int32_t foo, int32_t qux, int32_t baz, void* bar) {
printf("bar after: %p\n", bar);
return (ExampleStruct) {
.foo = foo,
.qux = qux,
.baz = baz,
.bar = bar
};
}
void test() {
void* bar = "fef";
printf("bar before: %p\n", bar);
foo(1, 1, 1, bar);
assert_int_equal(2,2);
}
int main() {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test),
};
return cmocka_run_group_tests_name("success_test", tests, NULL, NULL);
}
我得到以下输出:
[==========] Running 1 test(s).
[ RUN ] test
bar before: 0x40086f
bar after: 0x7f3ff17cb2cd
[ ERROR ] --- Test failed with exception: Segmentation fault(11)
[ FAILED ] test
[==========] 1 test(s) run.
[ PASSED ] 0 test(s).
[ FAILED ] 1 test(s), listed below:
[ FAILED ] test
如果我不使用包装函数,一切似乎都按预期工作。
更多详情
我是 运行 gcc 4.8.5 GNU ld 版本 2.27-44
问题
为什么向 ExampleStruct
添加另一个成员会导致分段错误?为什么 bar
在复制到 __wrap_foo
的参数时会改变值?
您需要添加 foo
函数的声明。当前 foo(1, 1, 1, bar);
将使用 int foo()
的隐式声明。自 C99 以来,隐式声明无效,因此您应该能够打开更多警告来捕获此问题 (-Wimplicit-function-declaration -Werror
)。
隐式声明的函数接受你给它的参数(这实际上匹配 __wrap_foo
,假设 int32_t
是 typedef
对 int
)和将 return int
,而不是 ExampleStruct
,因此您的程序将具有 未定义的行为。
示例:
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
typedef struct ExampleStruct {
int32_t foo;
int32_t qux;
int32_t baz;
void* bar;
} ExampleStruct;
// ** add this declaration **
ExampleStruct foo(int32_t foo, int32_t qux, int32_t baz, void* bar);
ExampleStruct __wrap_foo(int32_t foo, int32_t qux, int32_t baz, void* bar) {
printf("bar after : %p\n", bar);
return (ExampleStruct) {
.foo = foo,
.qux = qux,
.baz = baz,
.bar = bar
};
}
int main() {
void* bar = "fef";
printf("bar before: %p\n", bar);
foo(1, 1, 1, bar);
assert(2 == 2);
}