-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
prevent size overflows in the type system #17913
Comments
Here's an example of a simple program that segfaults on x86_64 OS X: fn main() {
let n = 0u;
let a = box [&n,..0xF000000000000000u];
println!("{}", a[0xFFFFFFu]);
} |
This seems to indicate that Rust can't correctly type-check generics from the definition alone. It needs to be aware of the type parameters in order to check for size overflows. Sizes are platform specific due to issues like alignment so valid types are platform specific. |
If a type has a size overflow then it can't exist, as it can't fit in memory. If you try to place it on the stack, you would get a stack overflow. This is, and should, be handled within trans. |
@arielb1: You're misunderstanding the issue. A type will a size overflow can certainly be created, as demonstrated by the example @zwarich gave. The size of the type has overflowed, so it's possible to create it because not enough space will be reserved. The problem is not limited to fixed-size arrays and can't be handled solely during initialization. The existence of the types actually needs to be considered invalid. |
Certainly they can be created now (due to the bug) – however, they should not be creatable (given that they take all address space). I think making |
The problem isn't limited to |
The size calculation code inside of the compiler (underlying |
@thestinger I agree, we should be careful in the trans paths, but it seems like ultimately this can be handled by checking for overflow in various places when constructing the LLVM version of a Rust type. e.g., when constructing an array type, we'd check that the size of the base type * the length doesn't overflow and so forth. Do you disagree? |
@nikomatsakis: The logic can be in trans, but it's not as simple as checking at construction of an array (multiplication overflow) / |
The overflow actually seems to happen within This can be observed by noticing that the following program prints 0: fn main() {
println!("{}", std::mem::size_of::<[u8, ..(1<<61)]>());
} Note that the size is |
#17795 seems like it could cause related issues. |
@arielb1: That's an unrelated issue, not the type system issue here. The issue I've reported here cannot occur with a fixed size array of |
Rust outsources the size calculations to several LLVM methods, including fn main() {
let s : [u8, ..(1<<61)] = [0, ..(1<<61)];
if s[0] == 0 { unreachable!() }
} Types with a size that can't be represented in a EDIT: Value constructors (e.g. |
The fixed-size array case was just an example, and there are other ways of turning this into a vulnerability. A size calculation is not necessary to trigger a bug with this. |
@thestinger can you elaborate on what you think will go wrong relating to the |
@nikomatsakis: We could detect it at any point where the type could be constructed but size calculations would need to be moved into Rust. If it's actually forbidden at compile-time rather than via an error at runtime, then it's a change in semantics because it will impact code generated via generics / macros but that's never actually called. |
I'm investigating this. It seems that size calculations are already halfway-in-Rust-halfway-in-LLVM, so this shouldn't be too bad. |
@thestinger OK. Regarding it being a change in semantics, I suppose that's technically true, but I don't think it's something we need to get too excited about. It's quite the edge case. I'd personally be inclined to just make it fail compilation eagerly rather than panic at runtime. But it's not a big thing and I could be persuaded the other way. Naturally it's a shame to repeat all size calculation on the Rust size, it'd be nice to avoid that. |
Assigning P-backcompat-lang, 1.0. |
…ektas fix: Add workspace level config to ratoml
Type size calculations inside the compiler can overflow, resulting in memory unsafety. Types without a valid
mem::size_of
should be forbidden to prevent unsoundness. Types that are valid today would become invalid and this would interfere with an attempt to support integer type parameters. I think it's a serious backwards compatibility issue since the interaction with generics is very bad.std::mem::size_of::<[[u8, ..!0u], ..!0u]>()
returns 1, since!0u * !0u
wraps to1
. The same thing can be done with other aggregate types like structs / tuples and an overflow could also occur from the tag added in anenum
.The text was updated successfully, but these errors were encountered: