How to be warned about pointers to out-of-scope local variables

浪尽此生 提交于 2019-12-23 21:01:07

问题


Consider the following code:

#include <stdio.h>

void badidea(int**);

int main(void) {
        int* p;
        badidea(&p);
        printf("%d\n", *p); /* undefined behavior happens here: p points to x from badidea, which is now out of scope */
        return 0;
}

void badidea(int** p) {
        int x = 5;
        *p = &x;
}

The intent seems to be that it will print 5, but it actually invokes undefined behavior, due to dereferencing a pointer to an out-of-scope local variable in main. How can I find instances of this problem in a codebase? Here's what I've tried so far:

  • Compiling with gcc -Wall -Wextra -pedantic
  • Compiling with clang -Weverything
  • Running having compiled with clang -fsanitize=undefined
  • Running under valgrind

None of the above produced any warnings.


回答1:


Compiling first with GCC 7.2 and without -fsanitize=address and then running under Valgrind produces the following:

==25751== Conditional jump or move depends on uninitialised value(s)
==25751==    at 0x4E988DA: vfprintf (vfprintf.c:1642)
==25751==    by 0x4EA0F25: printf (printf.c:33)
==25751==    by 0x1086E5: main (in ./a.out)

followed by other warnings.




回答2:


Our CheckPointer tool can detect this using dynamic analysis, along with a wide variety of other memory access errors. The tool tracks all allocations, accesses and assignments involving explicit or implicit pointers, and complains at the earliest moment when such an access is illegal or undefined.

Saving OP's example code as "buggy.c", and running CheckPointer produces the following output (some lines removed for pedagogical reasons):

C~GCC4 CheckPointer Version 1.2.1001
Copyright (C) 2011-2016 Semantic Designs, Inc; All Rights Reserved; SD Confidential Powered by DMS (R) Software Reengineering Toolkit
Parsing source file "E:/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c" using encoding CP-1252 +CRLF $^J $^M $^e -1 +8 ...
  Grouping top level declarations ...
  Creating object meta data initializers ...
  Normalizing syntax tree ...
  Instrumenting syntax tree ...
  Ungrouping top level declarations ...
Writing target file "E:/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Target/buggy.c" using encoding CP-1252 +CRLF $^J $^M $^e -1 +8 ...
*** Compiling sources with memory access checking code gcc.exe -I"e:\DMS\Domains\C\GCC4\Tools\CheckPointer" -I.\Target -obuggy.exe Target\buggy.c Target\check-pointer-data-initializers.c "e:\DMS\Domains\C\GCC4\Tools\CheckPointer\check-pointer.c" "e:\DMS\Domains\C\GCC4\Tools\CheckPointer\check-pointer-splay-tree.c" "e:\DMS\Domains\C\GCC4\Tools\CheckPointer\check-pointer-wrappers.c"
*** Executing instrumented application
*** Error: CWE-465 Pointer Issue (subcategory CWE-476, CWE-587, CWE-824, or CWE-825)
       Dereference of dangling pointer.
in function: main, line: 8, file E:/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c

The specific type of error is reported using codes defined by the Common Weakness Enumeration standard.

NIST offers a "torture" test for Java and C errors called Juliet. Of the 14,195 Juliet test cases that are relevant to the C language, CheckPointer detected 13257 expected memory-access errors. 908 test cases were not diagnosed, but these include ones that contain undefined behavior not related to pointer usage errors (which CheckPointer is not intended to detect), or pointer usage errors that were not exposed by the actual execution (e.g. uninitialized variable contained 0 in actual execution). [We modified some of these examples to ensure that the actual execution did not contain 0 for such variables, and afterwards CheckPointer gave an error message as expected.]

CheckPointer works with GCC and MSVisualStudio.

=======================================

@n.m. made a number of comments to various answers in this thread. He issued a kind of challenge problem where he demonstrated that valgrind can't find a bug in the following code, similar to OPs but more deeply nested:

#include <stdio.h>

void badidea(int**);
void worseidea(int**);

int main(void) {
    int* p;
    badidea(&p);
//        printf("%d\n", *p); /* undefined behavior happens here: p points to x from badidea, which is now out of scope */
    worseidea(&p);
    return 0;
}

void worseidea(int **p) {
    int x = 42;
    printf("%d %d\n", **p, x); /* undefined behavior happens here: p points to x from badidea, which is now out of scope */
}

void badidea(int** p) {
    int x = 5;
    *p = &x;
}

Here's the Checkpointer run, which does diagnose the pointer problem in n.m's code:

C~GCC4 CheckPointer Version 1.2.1001
Copyright (C) 2011-2016 Semantic Designs, Inc; All Rights Reserved; SD Confidential
...
Parsing source file "C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c" using encoding CP-1252 +CRLF $^J $^M $^e -1 +8 ...
  ...
Writing target file "C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Target/buggy.c" using encoding CP-1252 +CRLF $^J $^M $^e -1 +8 ...
*** Compiling sources with memory access checking code
gcc.exe -I"c:\DMS\Domains\C\GCC4\Tools\CheckPointer" -I.\Target -obuggy.exe Target\buggy.c Target\check-pointer-data-initializers.c "c:\DMS\Domains\C\GCC4\Tools\CheckPointer\check-
pointer.c" "c:\DMS\Domains\C\GCC4\Tools\CheckPointer\check-pointer-splay-tree.c" "c:\DMS\Domains\C\GCC4\Tools\CheckPointer\check-pointer-wrappers.c"
*** Executing instrumented application
*** Error: CWE-465 Pointer Issue (subcategory CWE-476, CWE-587, CWE-824, or CWE-825)
       Dereference of dangling pointer.
in function: worseidea, line: 16, file C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c
called in function: main, line: 10, file: C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c



回答3:


I don't think such mechanism exists in the C language, in the end pointers are simply variables holding addresses. When you give them a type it simply tells the compiler what kind of variable lies in the address space pointed by the pointer.Thus in theory pointer can hold any address values as long as it is in the defined address space.

And actually this is what makes C language really powerful. Espacially in data transferring mechanisms because you can send any type of data even the user defined structueres etc. in any order and receive/typecast in the other end easily without any concern of endiannes and such.

Though in your case , hopefully ,assuming you know your program's stack size and beginning address, You can check to see if the address content pointed by the pointer is in the area reserved for the Stack or not. Thus knowing if you are pointing to a local variable or not.

+If you must point to a local variable, you can define it as static, which place the variable outside of the stack in RAM. (You probably know it, but you know some might not.)



来源:https://stackoverflow.com/questions/52601540/how-to-be-warned-about-pointers-to-out-of-scope-local-variables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!