diff --git a/cpp/ql/src/Security/CWE/CWE-416/Temporaries.qll b/cpp/ql/src/Security/CWE/CWE-416/Temporaries.qll index 56d742b31d7..44880eee0b5 100644 --- a/cpp/ql/src/Security/CWE/CWE-416/Temporaries.qll +++ b/cpp/ql/src/Security/CWE/CWE-416/Temporaries.qll @@ -41,12 +41,21 @@ predicate isStoredInContainer(Expr e) { ) } + +/** + * Holds if `e` or a conversion of `e` has an lvalue-to-rvalue conversion. + */ +predicate hasLValueToRValueConversion(Expr e) { + e.getConversion*().hasLValueToRValueConversion() and + not e instanceof ConditionalExpr // ConditionalExpr may be spuriously reported as having an lvalue-to-rvalue conversion +} + /** * Holds if the value of `e` outlives the enclosing full expression. For * example, because the value is stored in a local variable. */ predicate outlivesFullExpr(Expr e) { - not e.getConversion*().hasLValueToRValueConversion() and + not hasLValueToRValueConversion(e) and ( any(Assignment assign).getRValue() = e or diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/UseOfStringAfterLifetimeEnds.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/UseOfStringAfterLifetimeEnds.expected index 7e33c948d2e..e6f64d57c99 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/UseOfStringAfterLifetimeEnds.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/UseOfStringAfterLifetimeEnds.expected @@ -9,4 +9,5 @@ | test.cpp:188:39:188:42 | call to data | The underlying string object is destroyed after the call to 'data' returns. | | test.cpp:189:44:189:47 | call to data | The underlying string object is destroyed after the call to 'data' returns. | | test.cpp:191:29:191:32 | call to data | The underlying string object is destroyed after the call to 'data' returns. | -| test.cpp:193:31:193:35 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. | +| test.cpp:193:47:193:51 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. | +| test.cpp:195:31:195:35 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/test.cpp index 51f85c91860..4b3d934088d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfStringAfterLifetimeEnds/test.cpp @@ -190,6 +190,8 @@ const char* test1(bool b1, bool b2) { char* s9; s9 = std::string("hello").data(); // BAD + const char* s13 = b1 ? std::string("hello").c_str() : s1; // BAD + return std::string("hello").c_str(); // BAD } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/UseOfUniquePointerAfterLifetimeEnds.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/UseOfUniquePointerAfterLifetimeEnds.expected index 8bd30062b57..3af8b501a66 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/UseOfUniquePointerAfterLifetimeEnds.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/UseOfUniquePointerAfterLifetimeEnds.expected @@ -6,4 +6,6 @@ | test.cpp:163:25:163:27 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. | | test.cpp:172:33:172:35 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. | | test.cpp:174:32:174:34 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. | -| test.cpp:176:11:176:11 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. | +| test.cpp:177:16:177:16 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. | +| test.cpp:177:36:177:36 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. | +| test.cpp:179:11:179:11 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/test.cpp index c1d55a28c17..22eec736df7 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseOfUniquePtrAfterLifetimeEnds/test.cpp @@ -173,6 +173,9 @@ const S* test1(bool b1, bool b2) { S* s5[] = { get_unique_ptr().get() }; // BAD + S s6 = b1 ? *get_unique_ptr() : *get_unique_ptr(); // GOOD + S& s7 = b1 ? *get_unique_ptr() : *get_unique_ptr(); // BAD + return &*get_unique_ptr(); // BAD }