因此在这个非常大的源文件中,我有以下部分,假设在函数foo
中,该函数从main
进行调用:
FILE *logfile = NULL
if (log_engabled) {
char fname[30];
snprintf(fname, 30, ".logs/%d.txt", time(NULL));
logfile = fopen(fname, "w");
}
fprintf(logfile, "test\n");
这执行没有问题。 (是的,我应该谨防logfile == NULL
,但为了简洁起见,我省略了它)。在我的测试运行中,log_file == 0x840fa50
和&log_file == 0x7ffffffedca8
。
然后我调用另一个函数bar
,该函数带有一堆参数,包括FILE **log_stream
。它的身体看起来像这样:
if (*log_stream)
fprintf(*log_stream, "test\n");
/*a bunch of other stuff, including more fprintf calls*/
现在这是奇怪的部分。如果我在上述代码段之后直接从bar
调用foo
,一切都会顺利进行。但是,稍后在foo
中,将使用其他参数和相同的bar
指针再次调用logfile
。然后,我在SIGSEGV
呼叫中得到一个fprintf
。我用gdb进行了检查,指针的位置以及它指向的值是完全相同的(并且我从不调用fclose
之间的指针)。
什么可能导致这种行为?它必须与我在bar
调用之间运行的代码有关,但是除了logfile
调用之外,这些语句中没有一个包含fprintf
。
也许我导致了fprintf
调用之外的段错误,并且gdb给了我错误的行号,但是我用gcc -O0和-g进行了编译,并且当我移动print语句时,错误指示。
我还尝试将logfile
声明为全局变量,并且没有将其传递给bar
,这无济于事。感谢您的帮助。
编辑:
我进行了一些挖掘和* drum roll *-问题是由无符号整数下溢引起的,该溢出导致超出范围的数组写入。更具体地说:
foo() {
FILE *logfile = fopen("log.txt", "w");
fprintf(logfile, "test1");
memory_corrupting_function();
fprintf(logfile, "test2");
}
第一个fprintf
再次平稳运行,第二个触发SIGSEGV
。因此,重新解释一下我的原始问题:如果不再次调用fprintf
,看程序如何继续正常运行,为什么在我调用fprintf
时而不是在我写到无效的内存位置?
甚至有答案吗?还是只是不确定的行为会在实现之间发生变化?
答案 0 :(得分:1)
您不能返回局部变量的地址。 logfile
很可能会存在于堆栈中。一旦foo
返回,很有可能会将logfile
持有的任何值覆盖。 fopen()
返回的文件指针在您fclose()
之前将一直有效。但是一旦函数返回,变量logfile
将超出范围。
只需返回logfile
的值:
FILE * foo() {
FILE *logfile = NULL;
//....
return logfile;
}
void bar() {
FILE *alsoLogfile = foo();
// ...
}
在您的问题中,您声明:如果我在上述代码段之后直接从foo调用bar,则一切运行都将顺利进行。这很可能是因为堆栈的一部分位于logfile
存在尚未被覆盖。使用范围外变量的地址是未定义的行为,因此任何事情都可能发生。