在C代码中获取valgrind错误

时间:2018-01-13 21:06:22

标签: c memory-management valgrind

我正在使用Valgrind在小应用程序的C代码上运行内存分析,它使用DFS方法找出图中的所有路径。但我仍然遇到一些错误,主要是在这部分代码中:

public static IEnumerable<T> InsertInOrder<T>(
    this IEnumerable<T> source,
    T insertion) where T : IComparable<T>
{
    using (var e = source.GetEnumerator())
    {
        while (e.MoveNext())
        {
            if (e.Current.CompareTo(insertion) < 0)
            {
                yield return e.Current;
            }
            else
            {
                yield return insertion;
                yield return e.Current;
                goto continueEnumerating;
            }
        }

        yield return insertion;
        goto exit;

    continueEnumerating:
        while (e.MoveNext())
        {
            yield return e.Current;
        }

    exit:
        yield break;
    }

我得到了这些valgrind错误:

int process_edges(VoidStack *edges, char *buffer)
{
    char weight[DATE_LENGTH] = "";
    char min_weight[DATE_LENGTH] = "", max_weight[DATE_LENGTH] = "";

    int metric;

    VoidStack *reverse = malloc(sizeof(VoidStack));
    void_stack_new(reverse, DATE_LENGTH);

    /* Create reverse stack to have edges in correct order */
    while (edges->loglength != 0)
    {
         void_stack_pop(edges, weight);
         void_stack_push(reverse, weight);
    }

    if (reverse->loglength >= 1)
    {
        void_stack_pop(reverse, weight);

        strcpy(max_weight, weight);
        strcpy(min_weight, weight);

        sprintf(buffer + strlen(buffer), "%s", weight);

        void_stack_push(edges, weight);
}

我不知道如何修复这些错误。

我正在使用这些参数运行Valgrind

  

- leak-check = full --track-originins = yes --show-reachable = yes

整个代码位于https://github.com/AdamPalaxo/KIV-PC

编辑:

添加了==1399== Conditional jump or move depends on uninitialised value(s) ==1399== at 0x4C2C2AB: strcpy (vg_replace_strmem.c:458) ==1399== by 0x4010D5: process_edges (in /home/adam/C/dfs.out) ==1399== by 0x401508: dfs (in /home/adam/C/dfs.out) ==1399== by 0x4015A9: dfs (in /home/adam/C/dfs.out) ==1399== by 0x40172A: all_paths (in /home/adam/C/dfs.out) ==1399== by 0x401AEC: main (in /home/adam/C/dfs.out) ==1399== Uninitialised value was created by a stack allocation ==1399== at 0x40100D: process_edges (in /home/adam/C/dfs.out) ==1399== ==1399== Conditional jump or move depends on uninitialised value(s) ==1399== at 0x4C2C2AB: strcpy (vg_replace_strmem.c:458) ==1399== by 0x4010E8: process_edges (in /home/adam/C/dfs.out) ==1399== by 0x401508: dfs (in /home/adam/C/dfs.out) ==1399== by 0x4015A9: dfs (in /home/adam/C/dfs.out) ==1399== by 0x40172A: all_paths (in /home/adam/C/dfs.out) ==1399== by 0x401AEC: main (in /home/adam/C/dfs.out) ==1399== Uninitialised value was created by a stack allocation ==1399== at 0x40100D: process_edges (in /home/adam/C/dfs.out) void_stack_newvoid_stack_push函数的代码。

void_stack_pop

1 个答案:

答案 0 :(得分:0)

OP在评论中发布了这个

  

好的,谢谢。我还添加了初始化堆栈的函数void_stack_new。   值s->element_size保持11,因为输入数据的格式为YYYY-MM-DD加上我   考虑\0终止字节。所以堆栈总是期望输入   总是大小相同。

我想,我解决了这个问题。我用你的堆栈代码自己做了一些测试

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct stack {
    int element_size;
    int loglength;
    int allocated_length;
    void *elements;
} VoidStack;

// I did copy & paste of your posted code
// not showing it here because it makes the code
// too long

void void_stack_print(VoidStack *s)
{
    char el[11];
    printf("Void Stack, element size: %d, #elements: %d, max #elements: %d\n",
            s->element_size, s->loglength, s->allocated_length);

    printf("Elements as strings:\n");
    for(int i = 0; i < s->loglength; ++i)
    {
        memcpy(el, ((char*) s->elements) + s->element_size * i, s->element_size);
        printf(" - %s\n", el);
    }

    puts("");
}

int main(void)
{
    VoidStack stack;

    void_stack_new(&stack, 11);

    void_stack_push(&stack, "2012-01-01");
    void_stack_push(&stack, "2012-01-02");
    void_stack_push(&stack, "2012-01-03");
    void_stack_push(&stack, "2012-01-04");

    void_stack_print(&stack);

    void_stack_push(&stack, "2013-01-01");
    void_stack_push(&stack, "2013-01-02");

    void_stack_print(&stack);

    char date[11], copy[11];

    void_stack_pop(&stack, date);
    strcpy(copy, date);
    printf("date: %s, copy: %s\n", date, copy);
    void_stack_print(&stack);

    void_stack_pop(&stack, date);
    strcpy(copy, date);
    printf("date: %s, copy: %s\n", date, copy);
    void_stack_print(&stack);


    free(stack.elements);
    return 0;
}

我的valgrind告诉我这个:

==748== Memcheck, a memory error detector
==748== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==748== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==748== Command: ./a
==748== 
Void Stack, element size: 11, #elements: 4, max #elements: 4
Elements as strings:
 - 2012-01-01
 - 2012-01-02
 - 2012-01-03
 - 2012-01-04

Void Stack, element size: 11, #elements: 6, max #elements: 8
Elements as strings:
 - 2012-01-01
 - 2012-01-02
 - 2012-01-03
 - 2012-01-04
 - 2013-01-01
 - 2013-01-02

date: 2013-01-02, copy: 2013-01-02
Void Stack, element size: 11, #elements: 5, max #elements: 8
Elements as strings:
 - 2012-01-01
 - 2012-01-02
 - 2012-01-03
 - 2012-01-04
 - 2013-01-01

date: 2013-01-01
date: 2013-01-01, copy: 2013-01-01
Void Stack, element size: 11, #elements: 4, max #elements: 8
Elements as strings:
 - 2012-01-01
 - 2012-01-02
 - 2012-01-03
 - 2012-01-04

==748== 
==748== HEAP SUMMARY:
==748==     in use at exit: 0 bytes in 0 blocks
==748==   total heap usage: 3 allocs, 3 frees, 1,156 bytes allocated
==748== 
==748== All heap blocks were freed -- no leaks are possible
==748== 
==748== For counts of detected and suppressed errors, rerun with: -v
==748== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

但是,如果我将数据更改为推送

    void_stack_print(&stack);

    void_stack_push(&stack, "2013-01-01XXXXXXX");  // <--- see here
    void_stack_push(&stack, "2013-01-02");

    void_stack_print(&stack);

    char date[11], copy[11];

    void_stack_pop(&stack, date);
    strcpy(copy, date);
    printf("date: %s, copy: %s\n", date, copy);
    void_stack_print(&stack);

    void_stack_pop(&stack, date);
    strcpy(copy, date);
    printf("date: %s, copy: %s\n", date, copy);
    void_stack_print(&stack);

看看会发生什么:

date: 2013-01-02, copy: 2013-01-02
Void Stack, element size: 11, #elements: 5, max #elements: 8
Elements as strings:
 - 2012-01-01
 - 2012-01-02
 - 2012-01-03
 - 2012-01-04
 - 2013-01-01X

==813== Invalid write of size 1
==813==    at 0x4C2E1D8: strcpy (vg_replace_strmem.c:510)
==813==    by 0x108C50: main (a.c:92)
==813==  Address 0x1fff001000 is not stack'd, malloc'd or (recently) free'd
==813== 
==813== 
==813== Process terminating with default action of signal 11 (SIGSEGV)
==813==  Access not within mapped region at address 0x1FFF001000
==813==    at 0x4C2E1D8: strcpy (vg_replace_strmem.c:510)
==813==    by 0x108C50: main (a.c:92)
==813==  If you believe this happened as a result of a stack
==813==  overflow in your program's main thread (unlikely but
==813==  possible), you can try to increase the size of the
==813==  main thread stack using the --main-stacksize= flag.
==813==  The main thread stack size used in this run was 8388608.
==813== 
==813== HEAP SUMMARY:
==813==     in use at exit: 88 bytes in 1 blocks
==813==   total heap usage: 3 allocs, 2 frees, 1,156 bytes allocated
==813== 
==813== LEAK SUMMARY:
==813==    definitely lost: 0 bytes in 0 blocks
==813==    indirectly lost: 0 bytes in 0 blocks
==813==      possibly lost: 0 bytes in 0 blocks
==813==    still reachable: 88 bytes in 1 blocks
==813==         suppressed: 0 bytes in 0 blocks
==813== Rerun with --leak-check=full to see details of leaked memory
==813== 
==813== For counts of detected and suppressed errors, rerun with: -v
==813== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault

我得到了一个非常类似的错误,但我认为这解决了这个问题。 您的pushpop方法没有错误,它们会复制正确的数量 字节。问题是"2013-01-01XXXXXXXX"长于11个字符, push复制了11个字符,但没有'\0'终止字节 在这11个字节中。 strcpy但需要有效'\0' - 终止 字符串,但如果找不到,则错误。

我在评论中告诉你了

  

如果是字符串(例如weight),你在考虑\0终止字节吗?   真的是所有相同长度的字符串(您的堆栈期望输入始终具有相同的大小)吗?

我不是那么遥远,一个问题可能是DATE_LENGTH不够大,或者 由于某种原因,你推动的字符串长度超过11个字符。无论如何,你需要 确保不要推送任何大于10个字符的字符串。你的堆栈不知道 字符串和字符串长度,无论类型如何,它总是复制element_size个字节, 所以push方法的调用者有责任确保 没有字符串长度超过10个字符。

在执行初始推送之前使用调试器或添加printf并检查每一个 你推的字符串不超过10个字符。