From 7d6fb7f91a2deaab8855a8b2060d866d97029631 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 6 Jul 2022 21:52:13 +0200 Subject: [PATCH 1/3] C++: Rename LossyFunctionResultCast tests to be correctly named --- ...castFromBitfield.expected => LossyFunctionResultCast.expected} | 0 ...itDowncastFromBitfield.qlref => LossyFunctionResultCast.qlref} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/{ImplicitDowncastFromBitfield.expected => LossyFunctionResultCast.expected} (100%) rename cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/{ImplicitDowncastFromBitfield.qlref => LossyFunctionResultCast.qlref} (100%) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/ImplicitDowncastFromBitfield.expected b/cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/LossyFunctionResultCast.expected similarity index 100% rename from cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/ImplicitDowncastFromBitfield.expected rename to cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/LossyFunctionResultCast.expected diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/ImplicitDowncastFromBitfield.qlref b/cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/LossyFunctionResultCast.qlref similarity index 100% rename from cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/ImplicitDowncastFromBitfield.qlref rename to cpp/ql/test/query-tests/Likely Bugs/Conversion/LossyFunctionResultCast/LossyFunctionResultCast.qlref From 0b471c2007e66938250bea985afeb8f6851660e8 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 6 Jul 2022 21:53:12 +0200 Subject: [PATCH 2/3] C++: Improve LossyFunctionResultCast join order Before on wireshark: ``` Tuple counts for #select#ff@eca61bf2: 180100 ~2% {2} r1 = SCAN Type::Type::getUnderlyingType#dispred#f0820431#ff OUTPUT In.1, In.0 84 ~2% {2} r2 = JOIN r1 WITH project#Type::FloatingPointType#class#2e8eb3ef#fffff ON FIRST 1 OUTPUT Lhs.1, Rhs.0 2021 ~0% {2} r3 = JOIN r2 WITH Function::Function::getType#dispred#f0820431#fb_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 2437 ~0% {2} r4 = JOIN r3 WITH Call::FunctionCall::getTarget#dispred#f0820431#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.1, Rhs.1 2150 ~0% {2} r5 = r4 AND NOT LossyFunctionResultCast::whiteListWrapped#377b528a#f(Lhs.1) 2150 ~0% {2} r6 = SCAN r5 OUTPUT In.1, In.0 313 ~0% {3} r7 = JOIN r6 WITH exprconv ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0 313 ~0% {3} r8 = JOIN r7 WITH Cast::Conversion#class#1f33e835#b ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2 148 ~3% {2} r9 = JOIN r8 WITH Expr::Expr::isCompilerGenerated#f0820431#b ON FIRST 1 OUTPUT Lhs.2, Lhs.1 148 ~1% {3} r10 = JOIN r9 WITH Expr::Expr::getActualType#dispred#f0820431#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0 21 ~0% {3} r11 = JOIN r10 WITH Type::IntegralType#class#2e8eb3ef#ff ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.0 21 ~0% {3} r12 = JOIN r11 WITH Element::ElementBase::toString#dispred#f0820431#ff ON FIRST 1 OUTPUT Lhs.2, Lhs.1, Rhs.1 21 ~0% {2} r13 = JOIN r12 WITH Element::ElementBase::toString#dispred#f0820431#ff ON FIRST 1 OUTPUT Lhs.1, ("Return value of type " ++ Lhs.2 ++ " is implicitly converted to " ++ Rhs.1 ++ " here.") return r13 ``` After: ``` Tuple counts for #select#ff@a5a185eg: 20 ~0% {2} r1 = SCAN project#Type::FloatingPointType#class#2e8eb3ef#fffff OUTPUT In.0, In.0 20 ~0% {2} r2 = JOIN r1 WITH project#Type::FloatingPointType#class#2e8eb3ef#fffff ON FIRST 1 OUTPUT Lhs.1, Lhs.0 84 ~2% {2} r3 = JOIN r2 WITH Type::Type::getUnderlyingType#dispred#f0820431#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 2021 ~0% {2} r4 = JOIN r3 WITH Function::Function::getType#dispred#f0820431#fb_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 2437 ~0% {2} r5 = JOIN r4 WITH Call::FunctionCall::getTarget#dispred#f0820431#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.1, Rhs.1 2150 ~0% {2} r6 = r5 AND NOT LossyFunctionResultCast::whiteListWrapped#377b528a#f(Lhs.1) 2150 ~0% {2} r7 = SCAN r6 OUTPUT In.1, In.0 313 ~0% {3} r8 = JOIN r7 WITH exprconv ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0 313 ~0% {3} r9 = JOIN r8 WITH Cast::Conversion#class#1f33e835#b ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2 148 ~3% {2} r10 = JOIN r9 WITH Expr::Expr::isCompilerGenerated#f0820431#b ON FIRST 1 OUTPUT Lhs.2, Lhs.1 148 ~1% {3} r11 = JOIN r10 WITH Expr::Expr::getActualType#dispred#f0820431#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0 21 ~0% {3} r12 = JOIN r11 WITH Type::IntegralType#class#2e8eb3ef#ff ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.0 21 ~0% {3} r13 = JOIN r12 WITH Element::ElementBase::toString#dispred#f0820431#ff ON FIRST 1 OUTPUT Lhs.2, Lhs.1, Rhs.1 21 ~0% {2} r14 = JOIN r13 WITH Element::ElementBase::toString#dispred#f0820431#ff ON FIRST 1 OUTPUT Lhs.1, ("Return value of type " ++ Lhs.2 ++ " is implicitly converted to " ++ Rhs.1 ++ " here.") return r14 ``` --- cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql b/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql index dee723e2686..3cbcffe0ce3 100644 --- a/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql +++ b/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql @@ -44,7 +44,7 @@ predicate whiteListWrapped(FunctionCall fc) { from FunctionCall c, FloatingPointType t1, IntegralType t2 where - t1 = c.getTarget().getType().getUnderlyingType() and + pragma[only_bind_into](t1) = c.getTarget().getType().getUnderlyingType() and t2 = c.getActualType() and c.hasImplicitConversion() and not whiteListWrapped(c) From 6b2154eb8b464b58e44f3416824fe0bdd2285f35 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 11 Jul 2022 11:54:48 +0200 Subject: [PATCH 3/3] C++: Add tests for `AnalysedExpr::isNullCheck` and `AnalysedExpr::isValidCheck` --- .../controlflow/nullness/nullness.expected | 15 ++++++++++++ .../controlflow/nullness/nullness.ql | 9 ++++++++ .../controlflow/nullness/test.cpp | 23 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 cpp/ql/test/library-tests/controlflow/nullness/nullness.expected create mode 100644 cpp/ql/test/library-tests/controlflow/nullness/nullness.ql create mode 100644 cpp/ql/test/library-tests/controlflow/nullness/test.cpp diff --git a/cpp/ql/test/library-tests/controlflow/nullness/nullness.expected b/cpp/ql/test/library-tests/controlflow/nullness/nullness.expected new file mode 100644 index 00000000000..db5c795fd5b --- /dev/null +++ b/cpp/ql/test/library-tests/controlflow/nullness/nullness.expected @@ -0,0 +1,15 @@ +| test.cpp:9:9:9:9 | v | test.cpp:5:13:5:13 | v | is not null | is valid | +| test.cpp:10:9:10:10 | ! ... | test.cpp:5:13:5:13 | v | is null | is not valid | +| test.cpp:11:9:11:14 | ... == ... | test.cpp:5:13:5:13 | v | is null | is not valid | +| test.cpp:12:9:12:17 | ... == ... | test.cpp:5:13:5:13 | v | is not null | is valid | +| test.cpp:13:9:13:14 | ... != ... | test.cpp:5:13:5:13 | v | is not null | is valid | +| test.cpp:14:9:14:17 | ... != ... | test.cpp:5:13:5:13 | v | is null | is not valid | +| test.cpp:15:8:15:23 | call to __builtin_expect | test.cpp:5:13:5:13 | v | is not null | is valid | +| test.cpp:16:8:16:23 | call to __builtin_expect | test.cpp:5:13:5:13 | v | is null | is not valid | +| test.cpp:17:9:17:17 | ... && ... | test.cpp:5:13:5:13 | v | is not null | is valid | +| test.cpp:18:9:18:17 | ... && ... | test.cpp:5:13:5:13 | v | is not null | is not valid | +| test.cpp:19:9:19:18 | ... && ... | test.cpp:5:13:5:13 | v | is null | is not valid | +| test.cpp:20:9:20:18 | ... && ... | test.cpp:5:13:5:13 | v | is not null | is not valid | +| test.cpp:21:9:21:14 | ... = ... | test.cpp:5:13:5:13 | v | is null | is not valid | +| test.cpp:21:9:21:14 | ... = ... | test.cpp:7:10:7:10 | b | is not null | is valid | +| test.cpp:22:17:22:17 | b | test.cpp:7:10:7:10 | b | is not null | is valid | diff --git a/cpp/ql/test/library-tests/controlflow/nullness/nullness.ql b/cpp/ql/test/library-tests/controlflow/nullness/nullness.ql new file mode 100644 index 00000000000..ed1ba15aa2b --- /dev/null +++ b/cpp/ql/test/library-tests/controlflow/nullness/nullness.ql @@ -0,0 +1,9 @@ +import cpp + +from AnalysedExpr a, LocalScopeVariable v, string isNullCheck, string isValidCheck +where + a.getParent() instanceof IfStmt and + v.getAnAccess().getEnclosingStmt() = a.getParent() and + (if a.isNullCheck(v) then isNullCheck = "is null" else isNullCheck = "is not null") and + (if a.isValidCheck(v) then isValidCheck = "is valid" else isValidCheck = "is not valid") +select a, v, isNullCheck, isValidCheck diff --git a/cpp/ql/test/library-tests/controlflow/nullness/test.cpp b/cpp/ql/test/library-tests/controlflow/nullness/test.cpp new file mode 100644 index 00000000000..03369c811d5 --- /dev/null +++ b/cpp/ql/test/library-tests/controlflow/nullness/test.cpp @@ -0,0 +1,23 @@ +// semmle-extractor-options: -std=c++17 + +long __builtin_expect(long); + +void f(int *v) { + int *w; + bool b; + + if (v) {} + if (!v) {} + if (v == 0) {} + if ((!v) == 0) {} + if (v != 0) {} + if ((!v) != 0) {} + if(__builtin_expect((long)v)) {} + if(__builtin_expect((long)!v)) {} + if (true && v) {} + if (v && true) {} + if (true && !v) {} + if (!v && true) {} + if (b = !v) {} + if (b = !v; b) {} +}