diff --git a/rust/ql/lib/codeql/rust/security/AccessAfterLifetimeExtensions.qll b/rust/ql/lib/codeql/rust/security/AccessAfterLifetimeExtensions.qll index c404f13b5314..c0ba618a9c5e 100644 --- a/rust/ql/lib/codeql/rust/security/AccessAfterLifetimeExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/AccessAfterLifetimeExtensions.qll @@ -57,7 +57,8 @@ module AccessAfterLifetime { // parameter exists(Callable c | var.getParameter().getEnclosingCallable() = c and - scope.getParentNode() = c + scope.getParentNode() = c and + not var.getParameter() instanceof SelfParam ) } diff --git a/rust/ql/src/change-notes/2026-01-13-access-after-lifetime-ended.md b/rust/ql/src/change-notes/2026-01-13-access-after-lifetime-ended.md new file mode 100644 index 000000000000..9310c4237e95 --- /dev/null +++ b/rust/ql/src/change-notes/2026-01-13-access-after-lifetime-ended.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed false positives from the `rust/access-after-lifetime-ended` query, involving pointers to fields of `self`. diff --git a/rust/ql/test/query-tests/security/CWE-825/lifetime.rs b/rust/ql/test/query-tests/security/CWE-825/lifetime.rs index 05a099e903fb..7c47397aed36 100644 --- a/rust/ql/test/query-tests/security/CWE-825/lifetime.rs +++ b/rust/ql/test/query-tests/security/CWE-825/lifetime.rs @@ -857,3 +857,50 @@ pub fn test_generic() { let result = generic_caller::(); println!(" result = {result}"); } + +// --- self --- + +struct MyObjectWithGetters { + value: i64 +} + +impl MyObjectWithGetters { + pub fn new(_value: i64) -> Self { + Self { + value: _value + } + } + + pub unsafe fn get_ptr1(&self) -> *const i64 { + &raw const self.value // $ MISSING: Source[rust/access-after-lifetime-ended]=self_value + // (the returned pointer is valid as long as the containing object is) + } + + pub unsafe fn get_ptr2(self) -> *const i64 { + &raw const self.value // $ MISSING: Source[rust/access-after-lifetime-ended]=self_value + // (the returned pointer is valid as long as the containing object is) + } +} + +pub fn test_get_self() { + let ptr1: *const i64; + let ptr2: *const i64; + + unsafe { + let obj = MyObjectWithGetters::new(1111); + ptr1 = obj.get_ptr1(); + ptr2 = obj.get_ptr2(); + + let v1 = *ptr1; // GOOD + let v2 = *ptr2; // GOOD + println!(" v1 = {}", v1); + println!(" v2 = {}", v2); + } + + use_the_stack(); + + let v3 = unsafe { *ptr1 }; // $ MISSING: Alert[rust/access-after-lifetime-ended]=self_value + let v4 = unsafe { *ptr2 }; // $ MISSING: Alert[rust/access-after-lifetime-ended]=self_value + println!(" v3 = {} (!)", v3); + println!(" v4 = {} (!)", v4); // corrupt in practice +} diff --git a/rust/ql/test/query-tests/security/CWE-825/main.rs b/rust/ql/test/query-tests/security/CWE-825/main.rs index d14c5d463ece..762b4ecfa36f 100644 --- a/rust/ql/test/query-tests/security/CWE-825/main.rs +++ b/rust/ql/test/query-tests/security/CWE-825/main.rs @@ -215,4 +215,7 @@ fn main() { println!("test_generic:"); test_generic(); + + println!("test_get_self:"); + test_get_self(); }