c - valgrind : Conditional jump or move depends on uninitialised value using strlen() strncat()

标签 c initialization valgrind strlen

我正在用 C 语言编写一个 grep 程序。为了确定是否应将收到的当前行打印到屏幕上,我使用了一个名为 reportLineMatchRec 的函数。
在此函数中,我使用另一个名为 updateConExpWithStr2 的函数来解析 reportLineMatchRec() 中使用的字符串之一。
不幸的是,我不断收到 valgrind 错误,说在使用 strlen() 和 strncat() 时,该函数内部使用了未初始化的值,即使我初始化了所有值。

更新:我更新了函数updateConExpWithStr1()updateConExpWithStr2(),因此gcc警告消失了,现在我收到了一个valgrind错误(也在下面更新)。我添加到 valgrind check --track-origins=yes 参数,该参数指出初始化问题的根源在于 commandParser 模块内 fillRoundBrackets() 内的 malloc (添加以下)。我还是没能解决这个问题。

代码:

结构:

typedef enum {REGULAR, POINT, ROUND_BRACKETS, BRACKETS} partClassifier;

union expressionPartInfo {
    char xy[2];
    char *str1OrStr2;
    char regularChar;
}expressionPartInfo;

typedef struct partInExpression
{
    union expressionPartInfo expressionPartInfo ;
    partClassifier partClassifier;
} partInExpression;

typedef struct parsedCommandStruct 
{
    char *expressionToSearch;
    char *origExpressionToSearch;
    char *concatenatedExpression;
    int lengthOfOrigExpression;
    int numOfExpressionParts;
    bool a;
    int aNum;
    bool b;
    bool c;
    bool i;
    bool n;
    bool v;
    bool x;
    bool E;
    struct partInExpression *arrayOfExpressionParts;
} parsedCommandStruct;

更新了matchInLine.c相关函数:

void updateConExpWithStr1(parsedCommandStruct *parsedCommand,  char **endOfString, int partIndex, char **orPtr,
        int *str1size,char **orPtrcopy){
    char *copyStr1OrStr2 = malloc(parsedCommand->lengthOfOrigExpression+1);
    strcpy(copyStr1OrStr2, parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2);
    *endOfString = parsedCommand->concatenatedExpression+strlen(parsedCommand->concatenatedExpression);
    *orPtr = strstr(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2, "|");
    *orPtrcopy=(*orPtr)+1;
    **orPtr = '\0';
    *str1size = strlen(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2);
    strcat(parsedCommand->concatenatedExpression, parsedCommand->arrayOfExpressionParts[partIndex].
    expressionPartInfo.str1OrStr2);
    strcpy(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2, copyStr1OrStr2);
    free(copyStr1OrStr2);
}

void updateConExpWithStr2(parsedCommandStruct *parsedCommand, int partIndex, char **orPtr,
                          int const*str1size, char **endOfString, char **orPtrcopy){
    int str2size=0;
    **endOfString = '\0';
    str2size = strlen(*orPtrcopy);
    strncat(parsedCommand->concatenatedExpression, *orPtrcopy, str2size);
}


void reportLineMatchRecE(int partIndex, lineInText *currentLineToCheck, parsedCommandStruct *parsedCommand,
        int *linesAfterMatchCounterPtr, int *prevLinesCounter, int *matchFlag){
    int j=0; char *orPtr = NULL; int str1size = 0; char *endOfString = NULL; char *orPtrcopy = NULL;
    while(partIndex < parsedCommand->numOfExpressionParts){
        if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == REGULAR) {
            updateConExpWithRegChr(parsedCommand, &partIndex);
        }
        else if (parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == POINT){
            for (j = ASCII_LOWEST_CHAR; j < ASCII_HIGHEST_CHAR+1; j++) {
                updateConExpWithChr(j, parsedCommand, &endOfString);
                reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
                        prevLinesCounter, matchFlag);
                *endOfString='\0';
            }
            return;
        }
        else if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == BRACKETS){
            for (j = parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.xy[0];
            j < parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.xy[1]+1; j++) {
                updateConExpWithChr(j, parsedCommand, &endOfString);
                reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
                        prevLinesCounter, matchFlag);
                *endOfString='\0';
            }
            return;
        }
        else if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == ROUND_BRACKETS){
            updateConExpWithStr1(parsedCommand, &endOfString, partIndex, &orPtr ,&str1size, &orPtrcopy);
            reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
                    prevLinesCounter, matchFlag);
            updateConExpWithStr2(parsedCommand, partIndex, &orPtr, &str1size, &endOfString, &orPtrcopy);
            reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
                    prevLinesCounter, matchFlag);
            return;
        }
    }
    if(partIndex == parsedCommand->numOfExpressionParts){
        strcpy(parsedCommand->expressionToSearch, parsedCommand->concatenatedExpression);
        reportLineMatch(currentLineToCheck, *parsedCommand, linesAfterMatchCounterPtr, prevLinesCounter, matchFlag);
        return;
    }
}




commandParser.c相关函数:


int fillRoundBrackets(parsedCommandStruct *parsedCommand, int indexOfParts, char *str1OrStr2){
    parsedCommand->arrayOfExpressionParts[indexOfParts].partClassifier = ROUND_BRACKETS;
    char *placeOfClosingBracket = strstr(str1OrStr2, ")");
    int str12Size = placeOfClosingBracket-str1OrStr2 - 1;
    parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = NULL;
    parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = malloc(200);//str12Size+1);
    strncpy(parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2, str1OrStr2+1, str12Size);
    return str12Size+1;
}

void buildArrayOfExpressionParts(parsedCommandStruct *parsedCommand){
    int numOfParts = computeNumOfParts(parsedCommand->expressionToSearch); int i=0, indexOfParts=0;
    parsedCommand->arrayOfExpressionParts = NULL;
    parsedCommand->arrayOfExpressionParts = malloc(numOfParts * sizeof(partInExpression));
    for(i=0; i<(int)strlen(parsedCommand->expressionToSearch); i++)
    {
        if(parsedCommand->expressionToSearch[i] == '.')
        {
            parsedCommand->arrayOfExpressionParts[indexOfParts].partClassifier = POINT;
        }
        else if(parsedCommand->expressionToSearch[i] == '[')
        {
            fillBrackets(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i+1],
                    parsedCommand->expressionToSearch[i+3]);
            i=i+4;
        }
        else if(parsedCommand->expressionToSearch[i] == '(') {
            parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = NULL;
            i = i + fillRoundBrackets(parsedCommand, indexOfParts, parsedCommand->expressionToSearch + i);
        }
        else if(parsedCommand->expressionToSearch[i] == '\\')
        {
            fillRegularChar(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i+1]);
            i=i+1;
        }
        else {
            fillRegularChar(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i]);
        }
        indexOfParts++;
    }
}

void createAndFillCommand(int argc, char *argv[], parsedCommandStruct **parsedCommand) {
    int indexOfExpressionArg = INITIALIZED_VALUE;
    indexOfExpressionArg = searchExpressionArgumentIndex(argc, argv);
    *parsedCommand = (parsedCommandStruct *) malloc(sizeof(struct parsedCommandStruct));
    initializeCommandArgs(parsedCommand);
    (*parsedCommand)->expressionToSearch =  (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
    strcpy((*parsedCommand)->expressionToSearch, argv[indexOfExpressionArg]);
    (*parsedCommand)->origExpressionToSearch =  (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
    strcpy((*parsedCommand)->origExpressionToSearch, argv[indexOfExpressionArg]);
    (*parsedCommand)->lengthOfOrigExpression = strlen((*parsedCommand)->expressionToSearch); // delete?
    (*parsedCommand)->numOfExpressionParts = computeNumOfParts((*parsedCommand)->expressionToSearch);
    updateArgumentsOfCommandStruct(argc, argv, *parsedCommand);
    if((*parsedCommand)->E){
        buildArrayOfExpressionParts(*parsedCommand);
        (*parsedCommand)->concatenatedExpression = (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
        strcpy((*parsedCommand)->concatenatedExpression, "");
    }

}

main.c:

void receiveAndExecute(parsedCommandStruct *parsedCommand, FILE **stream)
{
    ssize_t lineSize = INITIALIZED_VALUE; int matchFlag = 0;
    lineInText *currentLine = NULL;
    int lineIndex = FIRST_LINE_INDEX, counterForC = INITIALIZED_VALUE,
    linesAfterMatchCounter = INITIALIZED_VALUE, sumOfBytes = INITIALIZED_VALUE, prevLinesCounter = INITIALIZED_VALUE;
    currentLine = malloc(sizeof *currentLine);
    initializeCurrentLine(currentLine);

    while (1)
    {
        readLine(stream, &lineSize, currentLine);
        FillLineStruct(currentLine, lineIndex, sumOfBytes);
        sumOfBytes = (int)lineSize + sumOfBytes;
        lineIndex++;
        initializeConcatinateExp(parsedCommand);
        if(lineSize<0)
            break;
        reportLineMatchRec(0, currentLine, parsedCommand, &linesAfterMatchCounter, &prevLinesCounter, &matchFlag);
        printLineToOutput(currentLine, parsedCommand, &counterForC, false, &linesAfterMatchCounter,
                &prevLinesCounter, &matchFlag);
    }
    printLineToOutput(currentLine, parsedCommand, &counterForC, true, NULL, NULL, NULL);
    freeLine(&currentLine);
}

int main(int argc, char* argv[])
{
    parsedCommandStruct *parsedCommand = NULL;
    FILE *filePtr = NULL;
    bool useFile = false;
    useFile = isUsingFile(argc, argv);
    createAndFillCommand(argc, argv, &parsedCommand);

    if (useFile)
    {
        filePtr = openFile(argv[argc-1]);
        receiveAndExecute(parsedCommand, &filePtr);
        fclose(filePtr);
    }
    else
    {
        receiveAndExecute(parsedCommand, &stdin);
    }
    freeParsedCommandStruct(parsedCommand);
    free(parsedCommand);
    return 0;
}

更新了 valgrind 报告

==7832== Conditional jump or move depends on uninitialised value(s)
==7832==    at 0x4C2E1EB: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7832==    by 0x401BF7: updateConExpWithStr1 (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==    by 0x401F48: reportLineMatchRecE (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==    by 0x4020A4: reportLineMatchRec (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==    by 0x402280: receiveAndExecute (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==    by 0x402377: main (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==  Uninitialised value was created by a heap allocation
==7832==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7832==    by 0x40108C: fillRoundBrackets (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==    by 0x401218: buildArrayOfExpressionParts (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==    by 0x40142D: createAndFillCommand (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==    by 0x40233B: main (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==

最佳答案

将其从评论移至答案。

这段代码非常密集,很难粘贴到注释中,因此我添加了一些空格,并且我看到您已经删除了不必要的项目,例如转换malloc()的返回.

这都是关于编译器警告的内容,包括您没有收到的警告。

一般来说,编译器警告不是您修复的东西,而是您理解的东西。一旦您了解了它告诉您的内容,修复通常是免费且显而易见的。

warning: assignment makes pointer from integer without a cast

编译器告诉您,在下面标记的行中,一侧是整数,一侧是指针 - 是不是很清楚这里发生了什么:

void updateConExpWithStr1(parsedCommandStruct parsedCommand,  char **endOfString,
                          int partIndex, char **orPtr, int *str1size) {

    *endOfString = parsedCommand.concatenatedExpression
                 + strlen(parsedCommand.concatenatedExpression);

    *orPtr = strstr(
      parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
      "|");

    // THIS NEXT LINE IS WRONG
    str1size = *orPtr - parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2;

    strncat(parsedCommand.concatenatedExpression, 
            parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
            (size_t)str1size); // THIS LINE TOO
}

str1size 不是一个大小,它是一个指向大小的指针,所以这是有各种问题的。

所编写的代码在指针应在的位置存储了一个整数值,这意味着调用者看不到传回的大小。这可能是一个错误。

然后,后面标记为错误的行恰好可以正确运行,即使有两种错误。 strncat() 期望将大小作为第三个参数,但它给出了一个转换为整数的指针,这对于大小来说永远不是正确的事情,除了这次,因为整数未正确存储为指针。怎么样!

但是仅仅添加一个*只能解决技术问题,最好首先通过良好的命名约定来避免这种情况。如果你的函数是:

void updateConExpWithStr1(parsedCommandStruct parsedCommand,  char **endOfString,
                          int partIndex, char **orPtr, int *pStr1size) {
    ...
    *pStr1size = blah // integral result

    strncat(parsedCommand.concatenatedExpression, 
            parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
            *pStr1size);
}

这里我们不仅正确存储结果,而且通过更改名称来提醒您它是一个指针,让您更容易通过查看来判断这不仅仅是一个整数大小。

<小时/>

我希望这里的教训是,您应该认真对待编译器警告,以理解它们为目标,而不仅仅是让它们消失。

当您将 (size_t) str1size 放入对 strncat() 的调用中时,我非常确信您这样做是为了消除编译器警告您没有这样做的警告。不明白,那很危险。

通过添加强制转换,您告诉编译器“相信我”,因此这是一个隐藏在众目睽睽之下的错误(直到我写完这篇文章才注意到它)。

这是所有优秀 C 程序员都养成的一门纪律:渴望编译器警告,并理解每一个警告。始终将它们打开到最大,并且始终将它们包含在任何 SO 帖子中。

关于c - valgrind : Conditional jump or move depends on uninitialised value using strlen() strncat(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59432052/

相关文章:

c - 如何将参数传递给 xv6 的系统调用?

c - 如何将函数 srand() 与 time.h 一起使用?

c - OpenCL - 写入缓冲区为零?

c - 使 valgrind 在未初始化的值上快速失败

C++空程序内存泄漏

c - 如何处理错误: expected expression before ‘do’ when there is no “do” ?

javascript - 如何为我附加的 div 定义方法和属性?

c - 在外部结构初始化中将内部结构初始化为常量

c++ - Valgrind失败不失败CTest

c++ - AMPL API C++ - 如何设置变量的初始猜测?