【问题标题】:Valgrind reporting invalid write errorsValgrind 报告无效写入错误
【发布时间】:2010-11-18 19:39:34
【问题描述】:

这比我之前的 Valgrind 问题更集中;我试图在解析命令行选项时缩小写入和读取错误的范围:

#include <stdio.h>                                                                                                                                                                                                                    
#include <stdlib.h>                                                                                                                                                                                                                   
#include <unistd.h>                                                                                                                                                                                                                   
#include <sys/utsname.h>                                                                                                                                                                                                              
#include <sys/stat.h>                                                                                                                                                                                                                 
#include <string.h>                                                                                                                                                                                                                   
#include <locale.h>                                                                                                                                                                                                                   
#include <bzlib.h>                                                                                                                                                                                                                    
#include <zlib.h>                                                                                                                                                                                                                     
#include "starch.h"

#define BUFMAXLEN 1024

int main(int argc, char **argv) { 
    if (parseCommandLineInputs( &argc, &argv ) != 0)
        exit(EXIT_FAILURE);

    return 0;
} 

int parseCommandLineInputs(int *argc, char ***argv) {

    pid_t pid;                                                                                                                                                                                                                        
    struct utsname uts;
    char uniqTag[BUFMAXLEN];

    if ((*argc == 1) || (*argc > 4)) {                                                                                                                                                                                                
        printUsage();
        return -1;                                                                                                                                                                                                           
    }                                                                                                                                                                                                                                  

    if ((pid = getpid()) < 0) {                                                                                                                                                                                                       
        fprintf(stderr, "\n\t[starch] - Error: Could not obtain process ID\n\n");                                                                                                                                                     
        return -1;                                                                                                                                                                                                           
    }                                                                                                                                                                                                                                 
    uname( &uts );                                                                                                                                                                                                                    
    sprintf(uniqTag, "pid%d.%s", pid, uts.nodename);                                                                                                                                                                                  

    switch (*argc) {                                                                                                                                                                                                                  
        case 2: {                                                                                                                                                                                                                     
            if (strcmp(*argv[1], "-") != 0) {                                                                                                                                                                                         
                if (fileExists(*argv[1]) != 0) { /* standard input */                                                                                                                                                              
                    ...
    }

    return 0;
}


int fileExists(char *fn) {
    struct stat buf;
    int i = stat (fn, &buf);
    if (i == 0)
        return 0;
    return -1;
}

void printUsage() {
    fprintf(stderr, "my usage statement\n\n");
}

我的makefile如下:

CC      = gcc                                                                                                                                                                                                                         
CFLAGS  = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -DUSE_ZLIB -O3 -Wformat -Wall -pedantic -std=gnu99 -g                                                                                                                        
BIN     = ../bin                                                                                                                                                                                                                      

all: starch                                                                                                                                                                                                                           
    rm -rf *~                                                                                                                                                                                                                         

starch: starch.o                                                                                                                                                                                                                      
    mkdir -p $(BIN) && $(CC) ${CFLAGS} starch.o -lbz2 -lz -o ${BIN}/starch                                                                                                                                                            
    rm -rf *~                                                                                                                                                                                                                         

clean:
    rm -rf *.o *~ ${BIN}/starch

当我使用valgrind 运行时出现以下错误:

$ valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes -v ../bin/starch

...

==2675== 1 errors in context 1 of 2:                                                                                                                                                                                                  
==2675== Invalid read of size 8                                                                                                                                                                                                       
==2675==    at 0x3AB4262243: fwrite (in /lib64/libc-2.5.so)                                                                                                                                                                           
==2675==  Address 0x7fedffd68 is on thread 1's stack                                                                                                                                                                                  
==2675==                                                                                                                                                                                                                              
==2675==                                                                                                                                                                                                                              
==2675== 1 errors in context 2 of 2:                                                                                                                                                                                                  
==2675== Invalid write of size 8                                                                                                                                                                                                      
==2675==    at 0x401AA6: parseCommandLineInputs (starch.c:217)                                                                                                                                                                        
==2675==    by 0x7FF0000AF: ???                                                                                                                                                                                                       
==2675==    by 0x401DFA: main (starch.c:46)                                                                                                                                                                                           
==2675==  Address 0x7fedffd68 is on thread 1's stack 

第一个错误没有告诉我任何我可以使用的东西,因为我没有在任何地方使用fwrite()

printUsage() 中的 fprintf 语句引发了第二个错误。

第 46 行是以下行:

 if (parseCommandLineInputs( &argc, &argv ) != 0)

第 217 行是以下行:

 fprintf(stderr, "my usage statement\n\n");

我的应用程序有什么问题可以解释为什么会出现这些错误?

【问题讨论】:

  • 这不是完整的程序(没有#includes,没有utsuniqTagpid 的定义)。为什么parseCommandLineInputs 中的行都是尾随空格?
  • 您希望我们如何只用一半的信息调试您的程序? uts, uniqTag 在哪里?淀粉.c 的第 46 行和第 217 行是什么?你试过使用 --db-attach=yes 吗?

标签: c valgrind


【解决方案1】:

我马上想到了两件事:

  • *argv[1] 与 (*argv)[1] 不同,这可能是您的意思。数组下标优先于指针取消引用。这会导致指针无效。正如许多有经验的程序员会告诉你的那样:“不要试图记住运算符的优先级 - 如果有疑问,请使用括号,如果不直接使用它们”。

  • 编译器标志中的-O3 在调试时是一个很大的NO-NO。编译器会严重破坏你的代码,以至于让你的生活变得不可能。变量可以完全消失,函数可以在它们被内联时神秘地消失。如果您的代码使用 -O0 编译、链接和运行(IIRC 一些包含内联汇编的代码需要 -O1 和一些(全部?)GCC 版本)使用它,否则最多使用 -O1。

【讨论】:

  • 感谢您的帮助。我最终用strdup 语句替换了malloc/sprintf 语句。无论出于何种原因,这修复了 valgrind 错误消息。
【解决方案2】:

缺少太多东西,所以很难说出发生了什么。我想pidpid_t? 然后我唯一看到的是这个:

sprintf(uniqTag, "pid%d.%s", pid, uts.nodename);

pid_t 不一定是int,所以sprintf 在解析它的参数并弄乱你的堆栈时可能会走错路。但是gcc 应该告诉你如果你用-Wall 编译,我想这是。

尝试使用不同的编译器进行编译,例如 clang

【讨论】:

    猜你喜欢
    • 2013-02-07
    • 2017-06-29
    • 2014-08-18
    • 1970-01-01
    • 2020-08-12
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    相关资源
    最近更新 更多