-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
CFI: Fix LTO for #![no_builtins] crates with CFI
#156024
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # This file is automatically @generated by Cargo. | ||
| # It is not intended for manual editing. | ||
| version = 4 | ||
|
|
||
| [[package]] | ||
| name = "cfi-types" | ||
| version = "0.0.8" | ||
|
|
||
| [[package]] | ||
| name = "cross-lang-cfi-types-crate-abort" | ||
| version = "0.1.0" | ||
| dependencies = [ | ||
| "cfi-types", | ||
| ] | ||
|
|
||
| [[package]] | ||
| name = "cross-lang-cfi-types-crate-not-abort" | ||
| version = "0.1.0" | ||
| dependencies = [ | ||
| "cfi-types", | ||
| ] | ||
|
|
||
| [[package]] | ||
| name = "indirect-arity-mismatch-abort" | ||
| version = "0.1.0" | ||
|
|
||
| [[package]] | ||
| name = "indirect-pointee-type-mismatch-abort" | ||
| version = "0.1.0" | ||
|
|
||
| [[package]] | ||
| name = "indirect-return-type-mismatch-abort" | ||
| version = "0.1.0" | ||
|
|
||
| [[package]] | ||
| name = "indirect-type-mismatch-abort" | ||
| version = "0.1.0" | ||
|
|
||
| [[package]] | ||
| name = "indirect-type-qualifier-mismatch-abort" | ||
| version = "0.1.0" | ||
|
|
||
| [[package]] | ||
| name = "invalid-branch-target-abort" | ||
| version = "0.1.0" |
|
rcvalle marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Workspace mirroring the examples in <https://github.com/rcvalle/rust-cfi-examples>. | ||
| [workspace] | ||
| resolver = "2" | ||
| members = [ | ||
| "invalid-branch-target-abort", | ||
| "indirect-arity-mismatch-abort", | ||
| "indirect-pointee-type-mismatch-abort", | ||
| "indirect-return-type-mismatch-abort", | ||
| "indirect-type-qualifier-mismatch-abort", | ||
| "indirect-type-mismatch-abort", | ||
| "cross-lang-cfi-types-crate-abort", | ||
| "cross-lang-cfi-types-crate-not-abort", | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| [package] | ||
| name = "cross-lang-cfi-types-crate-abort" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| [dependencies] | ||
| cfi-types = { path = "../vendor/cfi-types" } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| include!("../shared_build_rs.rs"); | ||
|
|
||
| fn main() { | ||
| build_foo_static_lib(&[]); | ||
| } | ||
|
rcvalle marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| int | ||
| do_twice(int (*fn)(int), int arg) | ||
| { | ||
| return fn(arg) + fn(arg); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // This example demonstrates redirecting control flow using an indirect | ||
| // branch/call to a function with different return and parameter types than the | ||
| // return type expected and arguments intended/passed at the call/branch site, | ||
| // across the FFI boundary using the `cfi_types` crate for cross-language LLVM | ||
| // CFI. | ||
|
|
||
| use std::mem; | ||
|
|
||
| use cfi_types::{c_int, c_long}; | ||
|
|
||
| #[link(name = "foo")] | ||
| unsafe extern "C" { | ||
| fn do_twice(f: unsafe extern "C" fn(c_int) -> c_int, arg: i32) -> i32; | ||
| } | ||
|
|
||
| unsafe extern "C" fn add_one(x: c_int) -> c_int { | ||
| c_int(x.0 + 1) | ||
| } | ||
|
|
||
| unsafe extern "C" fn add_two(x: c_long) -> c_long { | ||
| c_long(x.0 + 2) | ||
| } | ||
|
|
||
| fn main() { | ||
| let answer = unsafe { do_twice(add_one, 5) }; | ||
|
|
||
| println!("The answer is: {}", answer); | ||
|
|
||
| println!("With CFI enabled, you should not see the next answer"); | ||
| let f: unsafe extern "C" fn(c_int) -> c_int = unsafe { | ||
| mem::transmute::<*const u8, unsafe extern "C" fn(c_int) -> c_int>(add_two as *const u8) | ||
| }; | ||
| let next_answer = unsafe { do_twice(f, 5) }; | ||
|
|
||
| println!("The next answer is: {}", next_answer); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| [package] | ||
| name = "cross-lang-cfi-types-crate-not-abort" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| [dependencies] | ||
| cfi-types = { path = "../vendor/cfi-types" } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| include!("../shared_build_rs.rs"); | ||
|
|
||
| fn main() { | ||
| build_foo_static_lib(&[]); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
|
|
||
| // This definition has the type id "_ZTSFvlE". | ||
| void | ||
| hello_from_c(long arg) | ||
| { | ||
| printf("Hello from C!\n"); | ||
| } | ||
|
|
||
| // This definition has the type id "_ZTSFvPFvlElE"--this can be ignored for the | ||
| // purposes of this example. | ||
| void | ||
| indirect_call_from_c(void (*fn)(long), long arg) | ||
| { | ||
| // This call site tests whether the destination pointer is a member of the | ||
| // group derived from the same type id of the fn declaration, which has the | ||
| // type id "_ZTSFvlE". | ||
| // | ||
| // Notice that since the test is at the call site and generated by Clang, | ||
| // the type id used in the test is encoded by Clang. | ||
| fn(arg); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| use cfi_types::c_long; | ||
|
|
||
| #[link(name = "foo")] | ||
| extern "C" { | ||
| // This declaration has the type id "_ZTSFvlE" because it uses the CFI types | ||
| // for cross-language LLVM CFI support. The cfi_types crate provides a new | ||
| // set of C types as user-defined types using the cfi_encoding attribute and | ||
| // repr(transparent) to be used for cross-language LLVM CFI support. This | ||
| // new set of C types allows the Rust compiler to identify and correctly | ||
| // encode C types in extern "C" function types indirectly called across the | ||
| // FFI boundary when CFI is enabled. | ||
| fn hello_from_c(_: c_long); | ||
|
|
||
| // This declaration has the type id "_ZTSFvPFvlElE" because it uses the CFI | ||
| // types for cross-language LLVM CFI support--this can be ignored for the | ||
| // purposes of this example. | ||
| fn indirect_call_from_c(f: unsafe extern "C" fn(c_long), arg: c_long); | ||
| } | ||
|
|
||
| // This definition has the type id "_ZTSFvlE" because it uses the CFI types for | ||
| // cross-language LLVM CFI support, similarly to the hello_from_c declaration | ||
| // above. | ||
| unsafe extern "C" fn hello_from_rust(_: c_long) { | ||
| println!("Hello, world!"); | ||
| } | ||
|
|
||
| // This definition has the type id "_ZTSFvlE" because it uses the CFI types for | ||
| // cross-language LLVM CFI support, similarly to the hello_from_c declaration | ||
| // above. | ||
| unsafe extern "C" fn hello_from_rust_again(_: c_long) { | ||
| println!("Hello from Rust again!"); | ||
| } | ||
|
|
||
| // This definition would also have the type id "_ZTSFvPFvlElE" because it uses | ||
| // the CFI types for cross-language LLVM CFI support, similarly to the | ||
| // hello_from_c declaration above--this can be ignored for the purposes of this | ||
| // example. | ||
| fn indirect_call(f: unsafe extern "C" fn(c_long), arg: c_long) { | ||
| // This indirect call site tests whether the destination pointer is a member | ||
| // of the group derived from the same type id of the f declaration, which | ||
| // has the type id "_ZTSFvlE" because it uses the CFI types for | ||
| // cross-language LLVM CFI support, similarly to the hello_from_c | ||
| // declaration above. | ||
| unsafe { f(arg) } | ||
| } | ||
|
|
||
| // This definition has the type id "_ZTSFvvE"--this can be ignored for the | ||
| // purposes of this example. | ||
| fn main() { | ||
| // This demonstrates an indirect call within Rust-only code using the same | ||
| // encoding for hello_from_rust and the test at the indirect call site at | ||
| // indirect_call (i.e., "_ZTSFvlE"). | ||
| indirect_call(hello_from_rust, c_long(5)); | ||
|
|
||
| // This demonstrates an indirect call across the FFI boundary with the Rust | ||
| // compiler and Clang using the same encoding for hello_from_c and the test | ||
| // at the indirect call site at indirect_call (i.e., "_ZTSFvlE"). | ||
| indirect_call(hello_from_c, c_long(5)); | ||
|
|
||
| // This demonstrates an indirect call to a function passed as a callback | ||
| // across the FFI boundary with the Rust compiler and Clang the same | ||
| // encoding for the passed-callback declaration and the test at the indirect | ||
| // call site at indirect_call_from_c (i.e., "_ZTSFvlE"). | ||
| unsafe { | ||
| indirect_call_from_c(hello_from_rust_again, c_long(5)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # This file is automatically @generated by Cargo. | ||
| # It is not intended for manual editing. | ||
| version = 4 | ||
|
|
||
| [[package]] | ||
| name = "cross-lang-integer-normalization-abort" | ||
| version = "0.1.0" |
|
rcvalle marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| [package] | ||
| name = "cross-lang-integer-normalization-abort" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| # Not a member of the parent `sanitizer-cfi-build-std-clang` workspace so it can | ||
| # be built with different `RUSTFLAGS` (i.e., integer normalization). | ||
| [workspace] | ||
| members = ["."] | ||
| resolver = "2" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| include!("../shared_build_rs.rs"); | ||
|
|
||
| fn main() { | ||
| build_foo_static_lib(&["-fsanitize-cfi-icall-experimental-normalize-integers"]); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| int | ||
| do_twice(int (*fn)(int), int arg) | ||
| { | ||
| return fn(arg) + fn(arg); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| // This example demonstrates redirecting control flow using an indirect | ||
| // branch/call to a function with different return and parameter types than the | ||
| // return type expected and arguments intended/passed at the call/branch site, | ||
| // across the FFI boundary using integer normalization for cross-language LLVM | ||
| // CFI. | ||
|
|
||
| use std::mem; | ||
|
|
||
| #[link(name = "foo")] | ||
| extern "C" { | ||
| fn do_twice(f: unsafe extern "C" fn(i32) -> i32, arg: i32) -> i32; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these perhaps use
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test is mainly to emphasize how the C integer types are encoded by their respective sizes when using integer normalization so I think it makes more sense the Rust side to have a sized integer types. Note all these tests are gated to only-x86_64-unknown-linux-gnu because of the naked_asm in the invalid-branch-target-abort test and to save CI resources anyway. |
||
| } | ||
|
|
||
| unsafe extern "C" fn add_one(x: i32) -> i32 { | ||
| x + 1 | ||
| } | ||
|
|
||
| unsafe extern "C" fn add_two(x: i64) -> i64 { | ||
| x + 2 | ||
| } | ||
|
|
||
| fn main() { | ||
| let answer = unsafe { do_twice(add_one, 5) }; | ||
|
|
||
| println!("The answer is: {}", answer); | ||
|
|
||
| println!("With CFI enabled, you should not see the next answer"); | ||
| let f: unsafe extern "C" fn(i32) -> i32 = unsafe { | ||
| mem::transmute::<*const u8, unsafe extern "C" fn(i32) -> i32>(add_two as *const u8) | ||
| }; | ||
| let next_answer = unsafe { do_twice(f, 5) }; | ||
|
|
||
| println!("The next answer is: {}", next_answer); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # This file is automatically @generated by Cargo. | ||
| # It is not intended for manual editing. | ||
| version = 4 | ||
|
|
||
| [[package]] | ||
| name = "cross-lang-integer-normalization-not-abort" | ||
| version = "0.1.0" |
|
rcvalle marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| [package] | ||
| name = "cross-lang-integer-normalization-not-abort" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| # Not a member of the parent `sanitizer-cfi-build-std-clang` workspace so it can | ||
| # be built with different `RUSTFLAGS` (i.e., integer normalization). | ||
| [workspace] | ||
| members = ["."] | ||
| resolver = "2" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| include!("../shared_build_rs.rs"); | ||
|
|
||
| fn main() { | ||
| build_foo_static_lib(&["-fsanitize-cfi-icall-experimental-normalize-integers"]); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
|
|
||
| // This definition has the type id "_ZTSFvlE". | ||
| void | ||
| hello_from_c(long arg) | ||
| { | ||
| printf("Hello from C!\n"); | ||
| } | ||
|
|
||
| // This definition has the type id "_ZTSFvPFvlElE"--this can be ignored for the | ||
| // purposes of this example. | ||
| void | ||
| indirect_call_from_c(void (*fn)(long), long arg) | ||
| { | ||
| // This call site tests whether the destination pointer is a member of the | ||
| // group derived from the same type id of the fn declaration, which has the | ||
| // type id "_ZTSFvlE". | ||
| // | ||
| // Notice that since the test is at the call site and generated by Clang, | ||
| // the type id used in the test is encoded by Clang. | ||
| fn(arg); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.