diff --git a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql index 6c3435eeba91..7b27a8529ce9 100644 --- a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql +++ b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql @@ -31,7 +31,9 @@ predicate useFunc(GlobalVariable v, Function f) { } predicate uninitialisedBefore(GlobalVariable v, Function f) { - f.hasGlobalName("main") + f.hasGlobalName("main") and + not initialisedAtDeclaration(v) and + not isStdlibVariable(v) or exists(Call call, Function g | uninitialisedBefore(v, g) and @@ -98,10 +100,16 @@ predicate callReaches(Call call, ControlFlowNode successor) { ) } +/** Holds if `v` has an initializer. */ +predicate initialisedAtDeclaration(GlobalVariable v) { exists(v.getInitializer()) } + +/** Holds if `v` is a global variable that does not need to be initialized. */ +predicate isStdlibVariable(GlobalVariable v) { v.hasGlobalName(["stdin", "stdout", "stderr"]) } + from GlobalVariable v, Function f where uninitialisedBefore(v, f) and useFunc(v, f) select f, - "The variable '" + v.getName() + + "The variable '" + v.getName() + "'" + " is used in this function but may not be initialized when it is called." diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql index dbe7f699d14d..cee3e65547b0 100644 --- a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql +++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql @@ -15,6 +15,8 @@ import cpp from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked where checked = v.getAnAccess() and + // The check can often be in a macro for handling exception + not checked.isInMacroExpansion() and dereferenced(checked) and unchecked = v.getAnAccess() and dereferenced(unchecked) and diff --git a/cpp/ql/src/change-notes/2024-04-09-reduce-FP.md b/cpp/ql/src/change-notes/2024-04-09-reduce-FP.md new file mode 100644 index 000000000000..d2d104d59cd8 --- /dev/null +++ b/cpp/ql/src/change-notes/2024-04-09-reduce-FP.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared. +* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion. \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/GlobalUseBeforeInit.expected b/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/GlobalUseBeforeInit.expected new file mode 100644 index 000000000000..789c03f902b3 --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/GlobalUseBeforeInit.expected @@ -0,0 +1 @@ +| test.cpp:27:5:27:6 | f1 | The variable 'b' is used in this function but may not be initialized when it is called. | diff --git a/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/GlobalUseBeforeInit.qlref b/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/GlobalUseBeforeInit.qlref new file mode 100644 index 000000000000..a186cc827ec5 --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/GlobalUseBeforeInit.qlref @@ -0,0 +1 @@ +Critical/GlobalUseBeforeInit.ql diff --git a/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/test.cpp b/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/test.cpp new file mode 100644 index 000000000000..fcecf6c5c44a --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/GlobalUseBeforeInit/test.cpp @@ -0,0 +1,38 @@ +typedef __builtin_va_list va_list; +typedef struct {} FILE; + +extern FILE * stdin; +extern FILE * stdout; +extern FILE * stderr; + +#define va_start(args, fmt) __builtin_va_start(args,fmt) +#define va_end(args) __builtin_va_end(args); + +int vfprintf (FILE *, const char *, va_list); + +int a = 1; +int b; + +int my_printf(const char * fmt, ...) +{ + va_list vl; + int ret; + va_start(vl, fmt); + ret = vfprintf(stdout, fmt, vl); + ret = vfprintf(stderr, fmt, vl); + va_end(vl); + return ret; +} + +int f1() +{ + my_printf("%d\n", a + 2); + my_printf("%d\n", b + 2); // BAD + return 0; +} + +int main() +{ + int b = f1(); + return 0; +} \ No newline at end of file