-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: Type inference for raw pointers #20950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+4,765
−72
Merged
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
6a2502c
Rust: Add type inference tests for raw pointers
paldepind 3e7a7d5
Rust: Include certain types in type inference tests
paldepind 785025f
Rust: Type inference for raw pointers
paldepind c15e12c
Rust: Accept test changes
paldepind ea1b0a8
Rust: Fix path resolution for raw pointer types
paldepind 236df0a
Rust: Accept changes to expected files
paldepind a05d0a9
Rust: Add change note for raw pointer type inference
paldepind 299fed5
Rust: Apply fixes from code review
paldepind 27ddc81
Rust: Cleanup of raw pointer types based in PR feedback
paldepind File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
rust/ql/lib/change-notes/2025-12-03-type-inference-raw-pointers.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| category: minorAnalysis | ||
| --- | ||
| * Improved type inference for raw pointers (`*const` and `*mut`). This includes type inference for the raw borrow operators (`&raw const` and `&raw mut`) and dereferencing of raw pointers. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -431,7 +431,10 @@ module CertainTypeInference { | |||||
| or | ||||||
| result = inferLiteralType(n, path, true) | ||||||
| or | ||||||
| result = inferRefNodeType(n) and | ||||||
| result = inferRefPatType(n) and | ||||||
| path.isEmpty() | ||||||
| or | ||||||
| result = inferRefExprType(n) and | ||||||
| path.isEmpty() | ||||||
| or | ||||||
| result = inferLogicalOperationType(n, path) | ||||||
|
|
@@ -606,10 +609,14 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat | |||||
| strictcount(Expr e | bodyReturns(n1, e)) = 1 | ||||||
| ) | ||||||
| or | ||||||
| ( | ||||||
| n1 = n2.(RefExpr).getExpr() or | ||||||
| n1 = n2.(RefPat).getPat() | ||||||
| ) and | ||||||
| exists(RefExpr re | | ||||||
| n2 = re and | ||||||
hvitved marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| n1 = re.getExpr() and | ||||||
| prefix1.isEmpty() and | ||||||
| prefix2 = TypePath::singleton(inferRefExprType(re).getPositionalTypeParameter(0)) | ||||||
| ) | ||||||
| or | ||||||
| n1 = n2.(RefPat).getPat() and | ||||||
| prefix1.isEmpty() and | ||||||
| prefix2 = TypePath::singleton(getRefTypeParameter()) | ||||||
| or | ||||||
|
|
@@ -709,9 +716,7 @@ private predicate lubCoercion(AstNode parent, AstNode child, TypePath prefix) { | |||||
| * of `n2` at `prefix2`, but type information should only propagate from `n1` to | ||||||
| * `n2`. | ||||||
| */ | ||||||
| private predicate typeEqualityNonSymmetric( | ||||||
| AstNode n1, TypePath prefix1, AstNode n2, TypePath prefix2 | ||||||
| ) { | ||||||
| private predicate typeEqualityAsymmetric(AstNode n1, TypePath prefix1, AstNode n2, TypePath prefix2) { | ||||||
| lubCoercion(n2, n1, prefix2) and | ||||||
| prefix1.isEmpty() | ||||||
| or | ||||||
|
|
@@ -723,6 +728,13 @@ private predicate typeEqualityNonSymmetric( | |||||
| not lubCoercion(mid, n1, _) and | ||||||
| prefix1 = prefixMid.append(suffix) | ||||||
| ) | ||||||
| or | ||||||
| // When `n2` is `*n1` propagate type information from a raw pointer type | ||||||
| // parameter at `n1`. The other direction is handled in | ||||||
| // `inferDereferencedExprPtrType`. | ||||||
| n1 = n2.(DerefExpr).getExpr() and | ||||||
| prefix1 = TypePath::singleton(getPtrTypeParameter()) and | ||||||
| prefix2.isEmpty() | ||||||
| } | ||||||
|
|
||||||
| pragma[nomagic] | ||||||
|
|
@@ -735,7 +747,7 @@ private Type inferTypeEquality(AstNode n, TypePath path) { | |||||
| or | ||||||
| typeEquality(n2, prefix2, n, prefix1) | ||||||
| or | ||||||
| typeEqualityNonSymmetric(n2, prefix2, n, prefix1) | ||||||
| typeEqualityAsymmetric(n2, prefix2, n, prefix1) | ||||||
| ) | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -2952,16 +2964,21 @@ private Type inferFieldExprType(AstNode n, TypePath path) { | |||||
| ) | ||||||
| } | ||||||
|
|
||||||
| /** Gets the root type of the reference node `ref`. */ | ||||||
| /** Gets the root type of the reference expression `ref`. */ | ||||||
| pragma[nomagic] | ||||||
| private Type inferRefNodeType(AstNode ref) { | ||||||
| ( | ||||||
| ref = any(IdentPat ip | ip.isRef()).getName() | ||||||
| or | ||||||
| ref instanceof RefExpr | ||||||
| private Type inferRefExprType(RefExpr ref) { | ||||||
| if ref.isRaw() | ||||||
| then | ||||||
| ref.isMut() and result instanceof PtrMutType | ||||||
| or | ||||||
| ref instanceof RefPat | ||||||
| ) and | ||||||
| ref.isConst() and result instanceof PtrConstType | ||||||
| else result instanceof RefType | ||||||
| } | ||||||
|
|
||||||
| /** Gets the root type of the reference node `ref`. */ | ||||||
| pragma[nomagic] | ||||||
| private Type inferRefPatType(AstNode ref) { | ||||||
| (ref = any(IdentPat ip | ip.isRef()).getName() or ref instanceof RefPat) and | ||||||
| result instanceof RefType | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -3145,6 +3162,21 @@ private Type inferIndexExprType(IndexExpr ie, TypePath path) { | |||||
| ) | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Gets the inferred type of `n` at `path` when `n` occurs in a dereference | ||||||
| * expression `*n` and when `n` is known to have a raw pointer type. | ||||||
| * | ||||||
| * The other direction is handled in `typeEqualityAsymmetric`. | ||||||
| */ | ||||||
| private Type inferDereferencedExprPtrType(AstNode n, TypePath path) { | ||||||
| exists(DerefExpr de, PtrType type, TypePath suffix | | ||||||
| de.getExpr() = n and | ||||||
| type = inferType(de.getExpr()) and | ||||||
|
||||||
| type = inferType(de.getExpr()) and | |
| type = inferType(n) and |
hvitved marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
hvitved marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
rust/ql/test/library-tests/elements/builtintypes/BuiltinTypes.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| use std::ptr::null_mut; | ||
|
|
||
| fn raw_pointer_const_deref(x: *const i32) -> i32 { | ||
| let _y = unsafe { *x }; // $ type=_y:i32 | ||
| 0 | ||
| } | ||
|
|
||
| fn raw_pointer_mut_deref(x: *mut bool) -> i32 { | ||
| let _y = unsafe { *x }; // $ type=_y:bool | ||
| 0 | ||
| } | ||
|
|
||
| fn raw_const_borrow() { | ||
| let a: i64 = 10; | ||
| let x = &raw const a; // $ type=x:TPtrConst.i64 | ||
| unsafe { | ||
| let _y = *x; // $ type=_y:i64 | ||
| } | ||
| } | ||
|
|
||
| fn raw_mut_borrow() { | ||
| let mut a = 10i32; | ||
| let x = &raw mut a; // $ type=x:TPtrMut.i32 | ||
| unsafe { | ||
| let _y = *x; // $ type=_y:i32 | ||
| } | ||
| } | ||
|
|
||
| fn raw_mut_write(cond: bool) { | ||
| let a = 10i32; | ||
| // The type of `ptr_written` must be inferred from the write below. | ||
| let ptr_written = null_mut(); // $ target=null_mut type=ptr_written:TPtrMut.i32 | ||
| if cond { | ||
| unsafe { | ||
| // NOTE: This write is undefined behavior because `ptr_written` is a null pointer. | ||
| *ptr_written = a; | ||
| let _y = *ptr_written; // $ type=_y:i32 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn raw_type_from_deref(cond: bool) { | ||
| // The type of `ptr_read` must be inferred from the read below. | ||
| let ptr_read = null_mut(); // $ target=null_mut type=ptr_read:TPtrMut.i64 | ||
| if cond { | ||
| unsafe { | ||
| // NOTE: This read is undefined behavior because `ptr_read` is a null pointer. | ||
| let _y: i64 = *ptr_read; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| pub fn test() { | ||
| raw_pointer_const_deref(&10); // $ target=raw_pointer_const_deref | ||
| raw_pointer_mut_deref(&mut true); // $ target=raw_pointer_mut_deref | ||
| raw_const_borrow(); // $ target=raw_const_borrow | ||
| raw_mut_borrow(); // $ target=raw_mut_borrow | ||
| raw_mut_write(false); // $ target=raw_mut_write | ||
| raw_type_from_deref(false); // $ target=raw_type_from_deref | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.