为什么我的价值不会增加?内存踩踏/堆栈故障?

时间:2010-10-15 22:04:25

标签: c memory stack

我遇到了一个相当迷人的虫子,我正试图绕过它。

我觉得我以前见过这个,但这次我想明白为什么会这样。

我有:

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;
}

4 个答案:

答案 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)宏重新评估副作用函数。 这是函数的客户端代码。