4 ms·
Conversion to and from C's `int` is one place where I think Rust is failing too :( Rust allows silent truncation of values in numeric conversions and considers
by pornel 11y ago
Conversion to and from C's `int` is one place where I think Rust is failing too :(
Rust allows silent truncation of values in numeric conversions and considers it "safe", because other features for memory safety will catch buffer overflows — but it doesn't care about cases where the program will do a memory-safe logically-invalid thing (e.g. write to a wrong location within a buffer).
That's because Rust has no integer size promotion at all, which means `len as usize` and `len as c_int` are required all over the place when interfacing with C (and the `as` operator has no overflow checking by design).
- aidenn0 11y agoI think integer size promotion would only make it worse. I do agree that "as" should have range checking. Some of it can be done statically (e.g. converting to a strictly larger type, and when the range of possible values are known) and the rest can be done with minimal overhead if they emit the code right.
- pcwalton 11y agoIt's not minimal overhead in many cases. Think about vectorization, for example.
- exDM69 11y agoRather than "type casts", implicit or explicit, I would like to see something with unambiguous, explicit semantics. Something like LLVM IR's operations, e.g. zero_extend, sign_extend, bitcast, floattoint, pointer_cast, etc. This may lead to some unnecessarily verbose code in some places but it leaves no surprises. It also gets rid of the need to do dirty tricks like union casts or pointer tricks when you want a bitcast from float to int or vice versa which is common when you write SIMD code, for example, using bitwise ops to extract the sign bit of a float or something like that.
- pcwalton 11y agoHow does the lack of integer size promotion make it easier to overflow? I don't follow.
- pornel 11y agoI want to convert between types without precision loss, but Rust has only option of no conversion at all, or a bug-prone conversion allowing precision loss. The problem is that `x as usize` will compile without warnings to something I didn't intend and causes bugs if usize is smaller than the type of `x`. AFAIK I can't avoid casts to `usize` any other way than using `usize` for almost every integer type in Rust. To make things worse my main use case for Rust is interfacing with C code, which means I have to deal with other types as often as `usize` and end up with these risky casts in almost every expression! It's awful. What I'd prefer is something (it could be another operator, but I'd prefer promotion to keep syntactical noise low) that would either compile if typeof(x) <= usize, or would not compile at all (i.e. if I write code that is accidentally 64-bit only, I want it to fail to compile on 32-bit machine, instead of merrily compiling to something that is buggy and will corrupt the data or even be exploitable through FFI which requires these casts that become unsafe).
- pcwalton 11y agoCouldn't you write that operator yourself? #[cfg(target_word_size="32")] struct ThisCastIsUnsafeFixIt; #[cfg(target_word_size="32")] const u64_to_usize: ThisCastIsUnsafeFixIt = ThisCastIsUnsafeFixIt; #[cfg(target_word_size="64")] fn u64_to_usize(x: u64) -> usize { x } ... u64_to_usize(123) // won't compile on 32-bit If "u64_to_usize" is too long of a name for you, then you should be able to do the same thing with a trait instead.
- pornel 11y ago> Couldn't you write that operator yourself? I guess I could (thanks for the tip - I didn't know about this cfg(), I've been trying with traits and sizeof::<>). But I'd prefer it to be in the language: • lossless integer type conversion seems like a very basic problem to me, that shouldn't need programmers to fix it themselves in a custom way in every crate. • even if I fix it in my code, I'm still worried about other people's code, because I assume that they also develop on x64 and unintentionally write casts that are subtly broken on smaller architectures.