我在C语言中遇到了一个彻头彻尾的奇怪问题,这似乎超出了我的基本调试能力。基本上,我正在使用一个简单的单元测试框架(CuTest)来为丑陋的(未记录的,无单元测试)代码库添加一些测试。我添加了一种新类型的单元测试,它基本上复制了已经存在的单元测试 - 但是对于代码中使用的64位整数。
此测试通常工作(正确评估相等比较),但是当它失败时,由于sprintf问题,它不会产生正确的错误消息。该函数如下所示:
/* Comparison Function for U64 Numbers */
void CuAssertU64Equals_LineMsg(CuTest* tc, const char* file, int line, const char* message, u64 expected, u64 actual) {
char buf[STRING_MAX];
if (expected == actual) return;
sprintf(buf, "expected <%lld> but was <%lld>", expected, actual);
CuFail_Line(tc, file, line, message, buf);
}
(注意:STRING_MAX是512,所以它应该足够大)。 (注2:在我正在使用的Cygwin系统上,u64是一个“long long int”变量)
当此测试失败时,产生的错误消息是奇怪的部分。无论“实际”的值是什么,它都会在该位置打印0。因此,给定expect = 1和actual = 2,消息将为:
"expected <1> but was <0>"
如果你切换参数的位置,并使其状态如下:
sprintf(buf, "actually <%lld> but expected <%lld>", actual, expected);
你得到输出:
"actually <2> but expected <0>"
毋庸置疑,这没什么意义,似乎表明某种奇怪的堆栈错误可能?说实话,我完全不清楚这样的错误是如何发生的 - 即使在原则上也是如此。我用CuTest代码做了一个小工作示例,它工作正常(没有将第二个设置为零)。这表明既不是CuTest,也不是函数本身就是问题。
但是,当与实际代码库一起使用时,它会遇到此问题。与环境(堆栈,内存或变量)相关的问题就是问题。
有没有人知道为什么会这样?我目前的候选理论是: 1.尝试读取数据时sprintf函数中的下溢/溢出。我不确定如何发生这种情况,因为传递给函数的任何数据都是按值计算的。此外,数据本身显然存在 - 如果我切换订单,我可以看到每个值。
我以某种方式使用了错误的格式。我非常确定lld对于长期的int来说是正确的(并且在我的最小工作示例中工作)但也许它很脆弱。
完全有关某种堆栈损坏。当然希望不是这个,因为我每周只工作20个小时。我怀疑我可以调试整个代码库来找出这么大的东西。
我目前正在cygwin环境中使用gcc-3进行编译,以获得它的价值。任何猜测都会很棒,我知道基本上不可能在没有看到整个代码库的情况下专门诊断它,但即使是一些关于调试这类问题的引导也会很棒。
答案 0 :(得分:4)
尝试使用“%I64d”作为格式字符串。我不确定Cygwin但我知道Visual Studio标准库的printf函数中的MinGW链接,造成各种各样的破坏。请注意任何新的C99功能和类型,如long double或size_t格式。
在这方面,有什么值得替换printf:
static char *CuPrintU64(char* buffer, u64 value) {
do
*--buffer = value % 10 + '0';
while(value /= 10);
return buffer;
}
/* Comparison Function for U64 Numbers */
void CuAssertU64Equals_LineMsg(CuTest* tc, const char* file, int line, const char* message, u64 expected, u64 actual) {
static const char first[] = "expected ";
static const char second[] = " but was ";
char buf[STRING_MAX], *ptr = &buf[sizeof buf];
if(expected == actual) return;
/* sprintf(buf, "expected <%llu> but was <%llu>", expected, actual); */
*--ptr = '\0';
ptr = CuPrintU64(ptr, actual);
ptr = memcpy(ptr - second, sizeof second - 1);
ptr = CuPrintU64(ptr, expected);
ptr = memcpy(ptr - first, sizeof first - 1);
CuFail_Line(tc, file, line, message, ptr);
}