Description
Related to #67946.
Currently, it's possible to perform a read to uninitialised memory by shadowing a function with an extern declaration with the same name. For example:
#[derive(Debug)]
struct Point {
x: i32,
y: i32
}
#[no_mangle]
fn bar(n: Point) {
println!("{:?}", n);
}
fn main() {
extern {
fn bar();
}
unsafe {
bar();
}
}
Output:
Point { x: 1014863296, y: 1421860952 }
Errors:
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/playground`
You can see we're able to happily print garbage this way. This is because on symbol name clash (but with different types), instead of erroring or otherwise doing work to produce distinct symbols, the function is bitcast instead. See #67946 (comment). In our example above, it means we produce a call to bar
as if it takes no arguments, meaning we read garbage if we access the function arguments. You can also produce garbage return values, by shadowing a function which has no return value with a declaration that does have a return value.
This issue has been assigned to @jumbatm via this comment.