我遇到了一个相当迷人的虫子,我正试图绕过它。
我觉得我以前见过这个,但这次我想明白为什么会这样。
我有:
int i;
int debug = 0;
for(i = 0; i < buf_end; i++) {
do_some_buffer_work();
if(something_is_true()) {
do_something_important();
printf("debug is %i, i is %i", debug++, i);
}
}
的printf( “端\ n”);
我得到了输出:
debug is 1, i is 55
debug is 2, i is 55
所以有一点是循环执行两次,i的值相同。 我在循环中所做的一切都没有直接触及我。此外,我怀疑这是传统的内存踩踏,因为价值总是相同的。我怀疑它是导致程序计数器移动的原因(因为有时连接错误会导致类似的错误),直到我做了以下测试:
int i;
static int debug;
for(i = 0; i < buf_end; i++) {
do_some_buffer_work();
if(something_is_true()) {
do_something_important();
printf("debug is %i, i is %i\n", debug++, i++);
printf("debug is %i, i is %i\n", debug++, i++);
printf("debug is %i, i is %i\n", debug++, i++);
}
}
printf("end\n");
我得到了这个有趣的输出:
debug is 0, i is 55
debug is 1, i is 56
debug is 2, i is 57
debug is 3, i is 55
debug is 4, i is 56
debug is 5, i is 57
end
所以这里显然已经执行了两次完全相同的迭代,但调试变量没有受到影响。由于某种原因,似乎正在缓存和恢复该值。我有一个预感并将调试变量更改为非静态并得到了这个:
int i;
int debug = 0;
for(i = 0; i < buf_end; i++) {
do_some_buffer_work();
if(something_is_true()) {
do_something_important();
printf("debug is %i, i is %i\n", debug++, i++);
printf("debug is %i, i is %i\n", debug++, i++);
printf("debug is %i, i is %i\n", debug++, i++);
}
}
printf("end\n");
我得到了这个有趣的输出:
debug is 0, i is 55
debug is 1, i is 56
debug is 2, i is 57
debug is 0, i is 55
debug is 1, i is 56
debug is 2, i is 57
end
所以看起来堆栈上的变量会重置到第55个开头 迭代。
我确信这个错误发生在其中一个do_something_important()调用中 - 它处理缓冲区读取 - 但是这个错误已经成为了自己的一个角色,我认为我应该对它有所了解在我压扁它之前的性质。 所以请不要试图帮助我修复它,如果你对它为何发生了一些线索,请告诉我。更具体地说,可以在程序状态中更改为“重置”这样的值吗?
编辑:如果有人因为我遗漏了这些功能而感到恼火,我很抱歉。它们非常庞大并且引用了其他功能,但我遗漏的主要原因是因为我不关心修复这个问题;我想知道如何以最简单的方式重新创建它。
第二编辑:这是布鲁斯发生的直接功能。包括引用的函数和所有子函数和定义可能大约有500行,所以我不是在这里做的。
static int find_headers_search(FCALParseContext *fpc, uint8_t *buf, int buf_size,
int search_start)
{
FCALFrameInfo fi;
int end_offset = -1, size = 0, i;
uint8_t *header_buf;
int debug = 0;
for (i = 0; i < buf_size - 1; i++) {
if ((AV_RB16(buf + i) & 0xFFFE) == 0xFFF8) {
av_log(NULL,AV_LOG_DEBUG,"predebug%i i %i\n",debug, i);
header_buf = fcal_fifo_read_wrap(fpc, search_start + i,
MAX_FRAME_HEADER_SIZE,
&fpc->wrap_buf,
&fpc->wrap_buf_allocated_size);
if (frame_header_is_valid(header_buf, &fi)) {
av_log(NULL,AV_LOG_DEBUG,"frame num %u bufstart %u, size %u, end %u i %i\n", (unsigned int)fi.frame_or_sample_num,
search_start, buf_size, search_start + buf_size -1, i);
FCALHeaderMarker **end_handle = &fpc->headers;
size = 0;
while (*end_handle) {
end_offset = (*end_handle)->offset;
end_handle = &(*end_handle)->next;
size++;
}
*end_handle = av_mallocz(sizeof(FCALHeaderMarker));
if (!*end_handle) {
av_log(fpc->avctx, AV_LOG_ERROR,
"couldn't allocate FCALHeaderMarker\n");
return AVERROR(ENOMEM);
}
(*end_handle)->fi = fi;
(*end_handle)->offset = search_start + i;
/* The actual size of the linked list is now size + 1 */
update_sequences(fpc, size - FCAL_MAX_SEQUENTIAL_HEADERS,
FFMIN(size, FCAL_MAX_SEQUENTIAL_HEADERS),
*end_handle);
fpc->nb_headers_found++;
size++;
av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++);
size = 0;
while (*end_handle) {
end_offset = (*end_handle)->offset;
end_handle = &(*end_handle)->next;
size++;
}
*end_handle = av_mallocz(sizeof(FCALHeaderMarker));
if (!*end_handle) {
av_log(fpc->avctx, AV_LOG_ERROR,
"couldn't allocate FCALHeaderMarker\n");
return AVERROR(ENOMEM);
}
(*end_handle)->fi = fi;
(*end_handle)->offset = search_start + i;
/* The actual size of the linked list is now size + 1 */
update_sequences(fpc, size - FCAL_MAX_SEQUENTIAL_HEADERS,
FFMIN(size, FCAL_MAX_SEQUENTIAL_HEADERS),
*end_handle);
fpc->nb_headers_found++;
size++;
av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++);
av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++);
av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++);
}
}
}
return size;
}
答案 0 :(得分:3)
有一个缓冲区,有一个buf_end,有一些'缓冲区工作'。所有在代码片段中都不可见。显然,有一些不可见的代码写入缓冲区的末尾,重写局部变量 debug 和 i 。在缓冲区末端设置数据断点,通常会在一两分钟内找到它。
答案 1 :(得分:2)
看起来像是递归/重入我。以下假设可以解释观察到的行为:
某些条件下的 do_some_buffer_work()
会调用包含此代码的函数。这可以解释静态是否一致以及本地人重新启动。您仅为i
的某些值看到它的原因是因为something_is_true()
仅适用于i
的值。
您应该在调试器中执行代码。在printf()的断点处观察调用堆栈将很快确定是否发生了递归。
答案 2 :(得分:1)
这可能有用也可能没有帮助(不知道do_some_buffer_work()
,something_is_true()
或do_something_important()
做什么妨碍分析的事情。但可以尝试在不同的地方设置2个循环计数器变量,并检查它们的不同之处:
int i;
static int ii;
int debug = 0;
for(i = 0, ii = 0; i < buf_end; i++, ii++) {
if (i != ii) debugBreak();
do_some_buffer_work();
if (i != ii) debugBreak();
if(something_is_true()) {
if (i != ii) debugBreak();
do_something_important();
printf("debug is %i, i is %i", debug++, i);
}
if (i != ii) debugBreak();
}
这可能会让你更接近事情的发展时间。
答案 3 :(得分:0)
问题是由于使用MAX(a,b)宏重新评估副作用函数。 这是函数的客户端代码。