News for hackers. Stuff that matters.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by cesarb on Tuesday July 20, 2021 @11:17AM (#27894789)
This kind of issue is the reason why some more modern languages like Rust or Go do not have implicit narrowing conversions. For instance, on Rust, trying to simply pass an usize (Rust's equivalent of size_t) to a function which expects an i32 (Rust's equivalent of int) will not compile; the programmer has to write "size as i32" (Rust's equivalent of "(int) size"), which makes it explicit that it might truncate the value at that point.

(Some Rust developers argue that even "size as i32" should be avoided, and "size.try_into()" should be used instead, since it forces the programmer to treat an overflow explicitly at runtime, instead of silently wrapping.)

Re:size_t-to-int vulnerability in Linux’s filesystem layer by derefr on Tuesday July 20, 2021 @12:16PM (#27895693)
> Some Rust developers argue that even "size as i32" should be avoided, and "size.try_into()" should be used instead, since it forces the programmer to treat an overflow explicitly at runtime, instead of silently wrapping.

It's important to still have the option for efficient truncating semantics, though; some software (e.g. emulators) needs to chunk large integers into 2/4/8 smaller ones, and rotation + truncating assignment is usually the cheapest way to do that.

But, importantly, this is a rare case. Most software that does demoting casts does not mean to achieve these semantics.

So I wonder — are there any low-level/systems languages where a demoting cast with a generated runtime check gets the simple/clean syntax-sugared semantics (to encourage/favor its use), while truncating demotion requires a clumsier syntax (to discourage its use)?

Re:size_t-to-int vulnerability in Linux’s filesystem layer by tialaramex on Tuesday July 20, 2021 @01:05PM (#27896344)
Right, this is a small infelicity in Rust, it is easier to write

  let x = size as i32;
... even if what you meant was closer to

  let x: i32 = size.try_into().expect("We are 100% sure size is small enough to fit into x");
But at least it isn't C or C++ where you might accidentally write

  x = size;
... and the compiler doesn't even warn you that size is bigger than x and you need to think about what you intended.

It's really hard to fix this in C++. Some of the Epoch proponents want to do so using epochs to get there, basically you'd have a "new" epoch of C++ in which narrowing must be explicit, and old code would continue to have implicit narrowing so it doesn't break.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by dkirill on Tuesday July 20, 2021 @01:14PM (#27896455)
> and the compiler doesn't even warn you that size is bigger than x

That's not true tho, compiler with reasonable flags set will definitely warn you and if you really don't like this kind of code you can force compiler to issue an error instead

Re:size_t-to-int vulnerability in Linux’s filesystem layer by simias on Tuesday July 20, 2021 @01:24PM (#27896567)
What flags you have in mind? Because this code doesn't generate any warning with GCC 11.1.0 with -Wall -Wextra:

    int main(void) {
        int some_int = 1234567;
        char c = some_int;

        return c;
    }
Re:size_t-to-int vulnerability in Linux’s filesystem layer by kllrnohj on Tuesday July 20, 2021 @01:36PM (#27896711)
Re:size_t-to-int vulnerability in Linux’s filesystem layer by aaronmdjones on Tuesday July 20, 2021 @01:33PM (#27896668)
-Wall -Wextra -Wpedantic does not enable all diagnostics.

This is GNU's idea of "all".

Contrast to Clang's -Weverything, which will.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by lazide on Tuesday July 20, 2021 @04:36PM (#27898955)
It seems though that the point is made, right? Even 'good' approaches miss on what should be a clear 'whoa, are you sure?' type warning. There are a lot of footguns wandering around in C/C++ land.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by BoorishBears on Tuesday July 20, 2021 @04:53PM (#27899169)
No, the point was you want don't get a warning and it will silently wrap. You can scroll up if you've forgotten.

And it is false. My default configuration C++ project created in Clion shows it very clearly, and even pesters to use int32/int64 over int/long.

But as usual the default fallback when you're wrong about C++ is "uh yeah but lotta footguns amirite"

As if there aren't enough that we need to start making them up...

Re:size_t-to-int vulnerability in Linux’s filesystem layer by opheliate on Wednesday July 21, 2021 @04:15AM (#27903694)
And yet RedHat's recommended compiler flags for GCC [0], for example, do not appear to catch the wrapping assignment in the above example code.

0: https://developers.redhat.com/blog/2018/03/21/compiler-and-l...

Re:size_t-to-int vulnerability in Linux’s filesystem layer by BoorishBears on Wednesday July 21, 2021 @10:19AM (#27906625)
Ah yes, of course the goalpost was "you need to customize your settings to catch it" above.

Now that the default in the most beginner friendly of IDEs catches it, the goalpost is "my pet source of customization designed with C++98 in mind doesn't catch this"

Of course, even your pet source of customization caught up: https://developers.redhat.com/blog/2021/04/06/get-started-wi...

Re:size_t-to-int vulnerability in Linux’s filesystem layer by opheliate on Wednesday July 21, 2021 @01:51PM (#27909591)
If by "caught up", you mean talked about clang-tidy in a separate post, which is definitely not a GCC compiler flag, then sure.

The goalpost, since you're insistent on being explicit about it, was whether a C/C++ compiler "with reasonable flags" will catch the implicit wrap. GCC is a very popular compiler, and to be honest, I'm still not sure how to get it to warn on the above code, if doing so is possible.

Edit: Just read the rest of the thread, it's -Wconversion, which I suppose makes sense. Ignore me, point taken.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by lazide on Wednesday July 21, 2021 @12:00PM (#27907995)
If said beginning friendly IDE is used by only a couple percent of the ecosystem, it seems disingenuous to use it as proof this isn't a problem in this context?
Re:size_t-to-int vulnerability in Linux’s filesystem layer by BoorishBears on Wednesday July 21, 2021 @01:02PM (#27908904)
Ok so we're going to keep shifting the goalposts, now it's "there aren't enough beginners relative to total usage so beginner friendly IDE isn't enough"...

I mean MSVS uses Clang-tidy too, Clang-tidy integrates style guides provided by Mozilla and Google.

Most C++ Google projects have clang-tidy configs.

Clang-tidy is literally table-stakes for modern C++ tooling.

Github shows 970,000 commits related to setting up clang-tidy

But uh, yeah, let's see where the goalpost skitters to next.

-

The irony is I said above, C++ has enough footguns without sticking your fingers in your ears and ignoring boring, easy to setup, widely well known and well used tooling.

But in the war against C++ no stone must be left unturned.

C++ is a tiny fraction of all the code I've written in my life but it irks me to no end that people can't deal with the idea that language safety can improve, that tooling can be considered part of that safety. Or rather they can... unless they're talking about C/C++

Re:size_t-to-int vulnerability in Linux’s filesystem layer by lazide on Wednesday July 21, 2021 @09:37PM (#27914359)
I’m definitely not moving any goalposts I know of!

I thought the point I had been making, as had others, is that by default this is an easy footgun.

There are all sorts of things that can be added on to all languages to help - if you know it’s a problem worth solving, etc. which is inevitably after you’ve footgunned yourself with it bad enough you felt the need to research how to prevent it.

Other languages just do the safer thing (or most compilers By default warn at least about common footguns) more - which is the whole point of this thread?

Re:size_t-to-int vulnerability in Linux’s filesystem layer by BoorishBears on Thursday July 22, 2021 @12:34PM (#27921023)
There was one point, C++ won't warn you by default .

But tooling that is incredibly common, that beginners will run into even if they take the path of least resistance, and experts will use because it enforces standards at the very least, covers it.

Like Js without linters is a minefield, but everyone accepts you should lint your Js. Why does that change when C++ is involved?

Re:size_t-to-int vulnerability in Linux’s filesystem layer by rocqua on Tuesday July 20, 2021 @02:21PM (#27897299)
The reason for this decision is so that compiler upgrades with -Wall and -Werror don't break builds.

I can see the reason behind it, but I feel that this behavior is something you opt into when you use -Werror.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by derefr on Tuesday July 20, 2021 @03:35PM (#27898206)
> The reason for this decision is so that compiler upgrades with -Wall and -Werror don't break builds.

It feels like the "right thing" here would instead be for the compiler to allow build scripts to reference a specific point-in-time semantics for -Wall.

For example, `-Wall=9.3.0` could be used to mean "all the error checks that GCC v9.3.0 knew how to run".

Or better yet (for portability), a date, e.g. `-Wall=20210720` to mean "all the error checks built into the compiler as of builds up-to-and-including [date]."

To implement this, compilers would just need to know what version/date each of their error checks was first introduced. Errors newer than the user's specifier, could then be filtered out of -Wall, before -Wall is applied.

With such a flag, you could "lock" your CI buildscript to a specific snapshot of warnings, just like you "lock" dependencies to a specific set of resolved versions.

And just like dependency locking, if you have some time on your hands one day, you could "unlock" the error-check-suite snapshot, resolve all the new error-checks introduced, and then re-lock to the new error-check-suite timestamp.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by HanyouHottie on Tuesday July 20, 2021 @04:06PM (#27898593)
Re:size_t-to-int vulnerability in Linux’s filesystem layer by antoinealb on Tuesday July 20, 2021 @04:12PM (#27898657)
I think it might be more of an headache: what if somebody fixes a bug in an analyzer so that it catches things it used to miss ? Should it be a breaking change ?

Personally i would vote for "Wall with Werror" means no guarantee for your build.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by wheybags on Tuesday July 20, 2021 @05:46PM (#27899803)
The real solution: leave Werror off by default, activate it only during CI builds
Re:size_t-to-int vulnerability in Linux’s filesystem layer by derefr on Wednesday July 21, 2021 @10:56AM (#27907163)
That's even worse, because then an upgrade to the compiler in the managed CI runner (e.g. Github Actions') base-image will translate to the same version of the code failing where it previously succeeded, with nobody sure why.

At least with -Werror on at all times, devs will tend to upgrade before the very-stable CI environment does, and thereby catch the problem at development time (usually less time-pressure) rather than release-cutting time (usually more time-pressure, esp. if the release is a hotfix.)

-----

Mind you, it does work to enable -Werror only in CI, if you lock your CI environment / compiler Docker image / etc. to a specific stable version, and treat that as the thing to re-lock in place of the "error-check suite snapshot version."

This has the disadvantage, though, that you can't take advantage of newly-stable/newly-unstable language features, or of newly-introduced compiler optimizations, without biting the bullet and taking on the work of fixing the errors introduced by re-locking the base-image.

With a separate flag for locking down the error-check-suite snapshot version, you could continue to upgrade the compiler — and thereby get access to new features / optimizations — while staying on a particular build regression "scope."

Re:size_t-to-int vulnerability in Linux’s filesystem layer by account42 on Thursday July 22, 2021 @04:35AM (#27916731)
> That's even worse, because then an upgrade to the compiler in the managed CI runner (e.g. Github Actions') base-image will translate to the same version of the code failing where it previously succeeded

If you don't want your build to fail on warnings, don't use -Werror. If you want it to only fail on specific warnings, use -Werror=...

> with nobody sure why

Unless they look at the errors in the compiler output. What does it matter if it was brought on by a compiler update or a push?

> At least with -Werror on at all times, devs will tend to upgrade before the very-stable CI environment does

Nothing wrong with -Werror for devs - the problem is when you ship code to others and leave -Werror on by default.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by GoblinSlayer on Wednesday July 21, 2021 @07:37AM (#27904929)
Is -Werror really supposed to not break builds?
Re:size_t-to-int vulnerability in Linux’s filesystem layer by account42 on Thursday July 22, 2021 @04:36AM (#27916741)
The whole point of -Werror is to break builds and -Wall / -Wextra are definitely not frozen. If you can't handle compiler updates resulting in errors, don't use -Werror in that environment.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by 130e13a on Tuesday July 20, 2021 @01:46PM (#27896822)
keep in mind though that -Weverything is not intended to be used in production: https://quuxplusone.github.io/blog/2018/12/06/dont-use-wever...
Re:size_t-to-int vulnerability in Linux’s filesystem layer by account42 on Thursday July 22, 2021 @04:38AM (#27916748)
-Weverything is great for CI though, in compination with lots of -Wno-... flags to disable warnings you don't want. Instead of having to manually look out for new warning flags you will get all automatically.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by aaronmdjones on Sunday July 25, 2021 @02:22PM (#27951558)
Yep, this is what I do; throw in -Weverything followed by a few things like -Wno-packed -Wno-padded -Wno-unused-parameter.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by gumby on Tuesday July 20, 2021 @04:59PM (#27899240)
> This is GNU's idea of "all".

Unfortunately, over the years people baked the semantics of -Wall into their builds so new diagnostics could not be added to that flag.

And clang’s -Weverything shows how the opposite can fail as well

Re:size_t-to-int vulnerability in Linux’s filesystem layer by not2b on Tuesday July 20, 2021 @06:27PM (#27900125)
There are some very wrong-headed warning options in gcc, such that turning them on and avoiding getting them will make your code worse. So -Wall means 'all recommended warnings'.

Also there are some warnings that won't be produced if you compile without optimization, because the needed analysis isn't performed.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by account42 on Thursday July 22, 2021 @04:50AM (#27916810)
And yet we have things like -Wmaybe-uninitialized in -Wall which by definition will occasionally warn on perfectly good code.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by ridiculous_fish on Tuesday July 20, 2021 @01:30PM (#27896632)
-Wconversion will do it.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by stjohnswarts on Tuesday July 20, 2021 @05:16PM (#27899459)
-Wconversion will catch this
Re:size_t-to-int vulnerability in Linux’s filesystem layer by rualca on Tuesday July 20, 2021 @01:58PM (#27897001)
>What flags you have in mind?

-Wconversion

https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

This is common knowledge for ages. Any cursory Google search returns countless answers.

Take this post made over a decade ago.

https://stackoverflow.com/questions/1730255/gcc-shouldnt-a-w...

Re:size_t-to-int vulnerability in Linux’s filesystem layer by tialaramex on Tuesday July 20, 2021 @01:33PM (#27896665)
Fair point although it seems "reasonable" varies from one platform to another, it doesn't warn out of the box for me but people have reported MSVC gets warnings here.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by nly on Tuesday July 20, 2021 @01:14PM (#27896457)
Narrowing within { } initialization is forbidden C++ now
Re:size_t-to-int vulnerability in Linux’s filesystem layer by jacoblambda on Tuesday July 20, 2021 @01:22PM (#27896544)
It can impact compile time performance but Boost Safe Numerics provides some nice wrappers to prevent narrowing (or restrict it to specific classes of narrowing) and throw warnings or errors at compile time similar to what you see in Rust.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by glaze on Tuesday July 20, 2021 @01:20PM (#27896526)
If you initialize it like this you get a warning:

x = { size };

Re:size_t-to-int vulnerability in Linux’s filesystem layer by frogblast on Tuesday July 20, 2021 @01:49PM (#27896875)
In swift:

    //  a is a UInt64
    let a = Int.random(in: 0..<Int.max)
    
    //  causes a fatal runtime error if out of range, halts execution
    let b = UInt32(a)
    
    //  returns a UInt32?, which will be nil if out of range
    let c =  UInt32(exactly: a)
    
    //  another approach for exact conversion:
    guard let d = UInt32(exactly: a) else {
        //  conversion failed
        //  handle error and return
        return
    }
    // 'd' is a UInt32 without any bits lost
    
    //  always succeeds, will return a UInt32, either clamped or truncated.   Truncation just cuts off the high bits.
    let e = UInt32(clamping: a)
    let f = UInt32(truncatingIfNeeded: a)
Re:size_t-to-int vulnerability in Linux’s filesystem layer by dathinab on Tuesday July 20, 2021 @01:15PM (#27896472)
As a interesting side note:

The "as" operator is often considered to have been a mistake. Both because of unchecked casts and because of "doing to much".

So I wouldn't be surprised if in the (very) long term there will be a rust edition deprecating `as` casts (after we have alternatives to all cast done with `as`, which are: Pointer casts, dyn casts/explicit coercion and truncating integer casts, for some we already have alternatives for on stable for other not).

And for all who want to not have `as` today you can combine extension traits (which internally still use `as`) + clippy lint against any usage of `as`.

EDIT: I forgot widening integer casts in the list above ;-).

Re:size_t-to-int vulnerability in Linux’s filesystem layer by eloff on Tuesday July 20, 2021 @01:30PM (#27896642)
I would prefer not to see that happen, I'm fine with as and the safer options as they are currently. It would be a big job to update all the code in the wild when you want to move to the newer edition.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by tialaramex on Tuesday July 20, 2021 @01:45PM (#27896816)
I don't see it as a big job. Am I wrong?

Imagine there's a suitable narrow::<type>() function introduced which has the same consequence, always narrowing, if your data was too wide it may drop important stuff on the floor, and narrow() just says that's too bad.

Rust 2030 can introduce narrow::<type>(), warn for narrowing as usage and then Rust 2035 can error for as. The Rust 2030 -> 2035 conversion software can consume code that does { x as y } and write { x.narrow::<y>() } instead. This code is not better but it's still working in Rust 2035 and this explicit narrow() function is less tempting for new programmers than as IMO.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by scns on Tuesday July 20, 2021 @04:29PM (#27898871)
Yes, BUT the correct thing to do would be more tedious to write that way.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by wizzwizz4 on Tuesday July 20, 2021 @01:41PM (#27896755)
You don't need to do that. Rust editions are fully backwards-compatible, since they can depend on code from different editions.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by eloff on Tuesday July 20, 2021 @02:24PM (#27897331)
I'm aware of that, which is why I specified when you want to move to the newer edition.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by cdirkx on Tuesday July 20, 2021 @03:48PM (#27898371)
Isn't this something that could be done automatically by rustfix?
Re:size_t-to-int vulnerability in Linux’s filesystem layer by chippiewill on Tuesday July 20, 2021 @02:26PM (#27897351)
> are there any low-level/systems languages where a demoting cast with a generated runtime check gets the simple/clean syntax-sugared semantics (to encourage/favor its use), while truncating demotion requires a clumsier syntax (to discourage its use)?

Not exactly the same thing, but in a related area C++ does this a bit.

In C++ you can always still do a c-style cast `(int) some_var` (and the implicit casts obviously), but in general you're meant to use the C++ style explicit casts like `static_cast` and `const_cast`. These are generally tidy, but the most powerful and dangerous of these casts is deliberately awkwardly named as `reinterpret_cast<int>(some_var)` rather than something terse.

It's always easy to spot during a code review.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by gumby on Tuesday July 20, 2021 @05:01PM (#27899280)
You can have your compiler warm about c-style casts
Re:size_t-to-int vulnerability in Linux’s filesystem layer by titzer on Tuesday July 20, 2021 @12:32PM (#27895925)
In Virgil, casts are written "type.!(expr)". Casts between numbers check ranges and roundability (for float<->int conversion). Reinterpreting the bits is written "type.view(expr)" and ignores signs, looks at the raw float bits, etc.

edit: a cast will throw an exception if it fails, in case that was not clear from context.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by londons_explore on Tuesday July 20, 2021 @12:51PM (#27896141)
It would be nice if CPU's had an instruction for "read the low 8 bits of this register, and require the high bits all be zeros (otherwise throw an exception)".

Then safety is free...

Re:size_t-to-int vulnerability in Linux’s filesystem layer by derefr on Tuesday July 20, 2021 @01:10PM (#27896410)
What does "otherwise throw an exception" mean at the CPU level?

I know Erlang's BEAM VM has a "fail jump pointer register", where instructions that can fail have relative-jump offsets encoded as immediates for those instructions, and if the instruction "fails" in whatever semantic sense, it takes the jump.

But most CPUs don't have anything like that.

Would you want it to trap, like with integer division by zero?

CPU traps are pretty hard to handle in most language runtimes, such that most compilers generate runtime checks to work around them, rather than attempting to handle them.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by simias on Tuesday July 20, 2021 @01:27PM (#27896599)
I assume they meant throwing an exception like divisions by zero usually do, i.e. a hardware trap.

I always thought that overflows should be checked in hardware, I suppose it's not a stretch to extend that to truncation. It's controversial though, and obviously mostly a thought experiment anyway unless we manage to convince some CPU manufacturer to extend their ISA that way.

MIPS does have (optional) trapping overflow on signed add/sub overflow, so at least there's a small precedent for it.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by ridiculous_fish on Tuesday July 20, 2021 @01:32PM (#27896657)
Swift checks all arithmetic by default: https://swift.godbolt.org/z/rW614G5aq

It seems obvious that future Apple CPUs will have hardware support for this, if they don't already.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by saagarjha on Tuesday July 20, 2021 @04:59PM (#27899243)
I don’t see this happening unless it makes it into the ARM ISA.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by gumby on Tuesday July 20, 2021 @05:04PM (#27899305)
I don’t know the terms of Apple’s license with ARM, do you? I’m quite interested.

Given that Apple was one of the original founders of ARM it’s quite possible that their license allows much more latitude anyone else’s.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by saagarjha on Tuesday July 20, 2021 @06:05PM (#27899962)
Adding new instructions to userspace programs is almost certainly not going to fly. All of their extensions have been hidden behind an opaque API, or limited to use in the kernel.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by masklinn on Wednesday July 21, 2021 @03:43AM (#27903462)
That… makes no architectural difference at all. As far as the architecture is concerned, these are architectural extensions either way: userspace programs can observably contain and execute instructions which are not standard ARM.

If AMX is allowed under their license, there is no reason why checked extensions would not be.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by ridiculous_fish on Wednesday July 21, 2021 @02:46AM (#27903048)
Apple benefits from compatibility with the ARM ecosystem, but there’s no downsides (from their perspective) from extending it. Their chips are “Apple Silicon”, setting the stage for forging ahead alone. I think it’s a card they hold in reserve, to be played when the time is right, like the Intel transition.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by hermitdev on Tuesday July 20, 2021 @06:00PM (#27899930)
I'm not familiar with ARM ISA, but from the godbolt disassembly, it doesn't look like anything special going on here - just the ASM being generated. What's happening here is it just does the add, jumps on overflow flag set to an invalid opcode...
Re:size_t-to-int vulnerability in Linux’s filesystem layer by saagarjha on Tuesday July 20, 2021 @06:06PM (#27899967)
The suggestion was a custom instruction or architectural extension to have this happen in hardware, rather than needing to write out extra code for this.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by WalterBright on Tuesday July 20, 2021 @01:01PM (#27896288)
D doesn't allow implicit narrowing conversions. The user has to have an explicit cast, like `cast(int) size`. Cast is made into a keyword so all those explicit conversions can be found with a simple grep.

We consider it best practice to try and organize the types such that explicit casts are minimized.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by titzer on Tuesday July 20, 2021 @12:30PM (#27895896)
This is a deep hole for language design.

I thought about this very, very carefully when designing Virgil[1]'s numerical tower, which has both fixed-size signed and unsigned integers, as well as floating point. Like other new language designs, Virgil doesn't have any implicit narrowing conversions (even between float and int). Also, any conversions between numbers include range/representability checks that will throw if out-of-range or rounding occurs. If you want to reinterpret the bits, then there's an operator to view the bits. But conversions that have to do with "numbers" then all make sense in that numbers then exist on a single number line and have different representations in different types. Conversion between always preserve numbers and where they lie on the number line, whereas "view" is a bit-level operation, which generally compiles to a no-op. Unfortunately, the implications of this for floating point is that -0 is not actually an integer, so you can't cast it to an int. You must round it. But that's fine, because you always want to round floats to int, never cast them.

[1] https://github.com/titzer/virgil

Re:size_t-to-int vulnerability in Linux’s filesystem layer by cjensen on Tuesday July 20, 2021 @12:43PM (#27896052)
C/C++ compilers commonly have warnings for narrowing conversions, and separate warnings for mixing signed/unsigned conversions for same-sized values.

While some folks aren't too fussed about warnings like this, those folks generally aren't writing secure code like kernels. I'm very surprised that kind of conversion was permitted in the code.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by ronsor on Tuesday July 20, 2021 @12:21PM (#27895762)
Shout out to Zig, which requires explicit casting also.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by baby on Tuesday July 20, 2021 @12:52PM (#27896159)
I wish clippy had a lint against downcasts specifically. I aso like that rust has no “int” type
Re:size_t-to-int vulnerability in Linux’s filesystem layer by jamincan on Wednesday July 21, 2021 @10:05AM (#27906460)
It does, you just need to enable it. There are a bunch of other cast-related lints as well that are allow by default.

https://rust-lang.github.io/rust-clippy/v0.0.212/#cast_possi...

Re:size_t-to-int vulnerability in Linux’s filesystem layer by baby on Wednesday July 21, 2021 @01:24PM (#27909236)
Oh wow, didn’t know about that one. Is this new?
Re:size_t-to-int vulnerability in Linux’s filesystem layer by pjmlp on Tuesday July 20, 2021 @01:03PM (#27896327)
Languages of the same age or older than C, also have explicit narrowing, but apparently that was seen as programming with a straightjacket.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by mgraczyk on Tuesday July 20, 2021 @11:50AM (#27895228)
That's cool! And some languages like Go don't even allow implicit widening conversions: https://play.golang.org/p/a5C5jsHypmu
Re:size_t-to-int vulnerability in Linux’s filesystem layer by est31 on Tuesday July 20, 2021 @11:53AM (#27895282)
Rust doesn't allow them either: https://play.rust-lang.org/?version=stable&mode=debug&editio...

Adding .into() works though, which is the recommended method if the conversion can be statically guaranteed (otherwise try_into should be used, which will become easier in the 2021 edition as the TryInto trait will become part of the prelude).

Re:size_t-to-int vulnerability in Linux’s filesystem layer by ridiculous_fish on Tuesday July 20, 2021 @12:28PM (#27895861)
into() does not work from size. It's rather frustrating in practice. https://stackoverflow.com/questions/62832438/why-is-rusts-us...
Re:size_t-to-int vulnerability in Linux’s filesystem layer by eloff on Tuesday July 20, 2021 @01:38PM (#27896729)
Yeah, that is frustrating since there are no platforms where that would fail today, and it's hard to imagine why we would ever want one with 256bit pointers.

We don't even use full 64bit pointers today on x64.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by fulafel on Tuesday July 20, 2021 @04:38PM (#27898981)
Maybe a fat pointer llvm target ala SoftBound running on a machine with 128 bit bare pointers, like as/400.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by est31 on Tuesday July 20, 2021 @03:57PM (#27898477)
When 16 bit computers went to 32 bit, people probably thought that one wouldn't ever need 64 bit computers either. That being said, by the time 128 bit run out we have probably boiled earths oceans :).

You could think of checked memory models where half of the 256 bit address is a 128 bit random key needed to access some allocation, or maybe even a decryption key. Similar things are done with the extra space of x64 as well.

Also, 128 bit numbers are still quite uncommon in Rust. Easy conversion of usize to them wouldn't be that useful if conversions of the other number types don't work.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by a1369209993 on Wednesday July 21, 2021 @02:16AM (#27902902)
> When 16 bit computers went to 32 bit, people probably thought that one wouldn't ever need 64 bit computers either.

People have said that about pretty much every memory size in the history of computing. The argument for 64-bit is not "2^64 bytes ought to be enough for anyone"; it's "you couldn't use more than 2^64 bytes even if you wanted to". Writing a full register worth of data every clock cycle at 4GHz works out to 32GB/s. (2^64B / 32GB/s) is just over seventeen years, to fill up a 64-bit address space, assuming you're doing no actual computation. Few computers even work for seventeen years without replacement, much less run single processes continually with no reboots.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by mgraczyk on Tuesday July 20, 2021 @02:59PM (#27897745)
The Ethereum virtual machine addresses it's storage with 256 bits, so there's one wild example. Although in this case you'd probably not want to use usize directly to represent storage.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by eloff on Tuesday July 20, 2021 @03:09PM (#27897890)
I'm not familiar with the Ethereum virtual machine, are these really memory pointers? Surely it's represented differently?
Re:size_t-to-int vulnerability in Linux’s filesystem layer by mgraczyk on Tuesday July 20, 2021 @03:59PM (#27898501)
EVM is a stack machine, and it has durable storage which is addressed using 256 bit "pointers". So you can do something like

    push x // 256 bit constant
    LOAD
    // top of stack now contains storage[x]
Re:size_t-to-int vulnerability in Linux’s filesystem layer by pornel on Tuesday July 20, 2021 @06:43PM (#27900234)
Even worse, there are platforms with >=128-bit pointers but 64-bit address space. Rust has chosen usize to be uintptr_t rather than size_t, even though it mostly uses it as if it was size_t. A ton of code is going to subtly break when these two sizes ever differ. Rust is likely already doomed on >64-bit platforms, and is going to be forced to invent its own version of a LLP64 workaround.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by TheCycoONE on Tuesday July 20, 2021 @08:50PM (#27901043)
Sorry, I'm not sure how this is a problem. On segmented architectures size_t is smaller than uintptr_t, but that just means there needs to be an allocation limit < usize::max_value.

It would have cause more bugs if they defined it the other way and people used usize to store addresses.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by dezgeg on Wednesday July 21, 2021 @04:43PM (#27911908)
"Fortunately" there will be bigger problems than Rust on 128-bit machines - lots of UAPI structures in the Linux kernel have pointer size hardcoded to 64 bits.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by masklinn on Tuesday July 20, 2021 @01:30PM (#27896635)
> It's rather frustrating in practice.

All explicit conversions, more so fallible, are "frustrating in practice" especially when coming from a language without those foibles.

But given the semantics of usize/isize, it is perfectly reasonable, nay, a good thing, that they're considered neither widenings nor narrowings of other numeric types.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by ridiculous_fish on Tuesday July 20, 2021 @03:20PM (#27897997)
usize should be Into<u64> iff usize is <= 64 bit.

usize is already on that hook: `0x100000000usize` will fail to compile in 32 bit, so you already risk compile errors when switching archs.

As it is I'm just writing `as u64` which is clearly worse.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by mnw21cam on Tuesday July 20, 2021 @11:28AM (#27894939)
Add Java to that list.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by csharptwdec19 on Tuesday July 20, 2021 @12:29PM (#27895884)
Same for C#. Any narrowing truncation needs to be an explicit cast. Widening is typically allowed implicitly, although in the case of the 'decimal' (128 bit struct representing a 'higher precision' floating point) type you still need an explicit cast from a 'double', since there are cases where that conversion can still change the value or fail (i.e. Infinity/NaN)
Re:size_t-to-int vulnerability in Linux’s filesystem layer by pjmlp on Tuesday July 20, 2021 @01:06PM (#27896357)
Microsoft is considering turning on by default checked arithmetic in the 2022 Visual Studio templates, by the way.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by irogers on Tuesday July 20, 2021 @05:02PM (#27899292)
It can catch people by surprise that Java's narrowing conversions may not preserve the sign. For example, the following is broken:

class TimestampedObject implements Comparable<TimestampedObject> { long timestamp; int compareTo(TimestampedObject other) { return (int)(timestamp - other.timestamp); } ... }

ErrorProne catches this: https://errorprone.info/bugpattern/BadComparable

Re:size_t-to-int vulnerability in Linux’s filesystem layer by paulddraper on Tuesday July 20, 2021 @03:15PM (#27897937)
Noo! This idea is super new and was invented by Go/Rust.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by mytailorisrich on Tuesday July 20, 2021 @01:04PM (#27896332)
The compiler can issue warnings for this.

This os why in C it is a good practice to enable all compiler warnings and to have the compiler treat warnings as errors.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by viraptor on Tuesday July 20, 2021 @03:29PM (#27898128)
In theory but not in practice if you're distributing your apps sources.

If you write for C compiler Foo 8, there's a decent chance Foo 9 will raise a warning which didn't exist before. Now you have to handle "why doesn't this compile" issues and distributions have to patch your sources to do future releases. And that's ignoring bugs like GCC in the past where in some versions you could not satisfy specific warnings.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by j1elo on Tuesday July 20, 2021 @07:17PM (#27900474)
The golden rule is: use -Werror for Debug builds, so you catch and fix all warnings during development. That's fair enough.

But never ever leave -Werror enabled for building in Release mode. You'll be preventing your code from building as soon as a new compiler version goes out. Maintainers or code archeologist will have a much worse time than if this option was simply disabled to start with.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by nly on Tuesday July 20, 2021 @01:17PM (#27896490)
Long and int are the same size on Windows. The fact that these sizes aren't well defined is the cause of the issue.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by phkahler on Tuesday July 20, 2021 @01:35PM (#27896690)
This wouldn't be a problem if "int" was defined as the same size as size_t. The solution is probably to change all those functions to take a parameter of size_t instead of int.

IMHO one should always be using C99 types instead of int, but Linux predates that.

Also, shouldn't that implicit conversion cause a compiler warning?

Re:size_t-to-int vulnerability in Linux’s filesystem layer by pcwalton on Tuesday July 20, 2021 @02:42PM (#27897532)
> This wouldn't be a problem if "int" was defined as the same size as size_t.

ILP64 causes a lot of problems, most notably needlessly-increased memory usage and, in C, the inconvenience of requesting a 32-bit type when int is 64-bit. It's rather uncommon to actually need the extra 64-bit range except when describing pointer addresses and memory/disk sizes, both of which benefit from an explicit intptr_t/size_t type for readability if nothing else.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by saagarjha on Tuesday July 20, 2021 @05:01PM (#27899267)
ILP64 also solves a lot of problems if you don’t define overflow to be UB.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by tialaramex on Tuesday July 20, 2021 @01:54PM (#27896952)
Linux apparently provides a similarly named set of sized integer types to Rust, ie: s8 u8 s16 u16 s32 u32 s64 u64

But of course getting C programmers to use these integer types rather than the ones they grew up with isn't easy.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by foobiekr on Tuesday July 20, 2021 @03:31PM (#27898165)
I did a lot of C - a lot - in the mid-90s through the mid/late 2000s and have never seen any sizable C code base where explicit sizes were not the norm throughout - u_int32_t etc. I think this is not the problem, it's the implicit conversions.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by masklinn on Wednesday July 21, 2021 @03:46AM (#27903479)
I don't think that stops C's implicit conversions either, does it?
Re:size_t-to-int vulnerability in Linux’s filesystem layer by dezgeg on Wednesday July 21, 2021 @10:37AM (#27906865)
It doesn't. They are in the end just typedefs to the basic types like int, long, etc.
Re:size_t-to-int vulnerability in Linux’s filesystem layer by chippiewill on Tuesday July 20, 2021 @02:29PM (#27897376)
> IMHO one should always be using C99 types instead of int, but Linux predates that.

"Always" is a strong way of putting it, there are often times where it makes sense to use the platform's "natural" word sizes (which is the entire point of having `int` `long` `long long` etc.)

Re:size_t-to-int vulnerability in Linux’s filesystem layer by phkahler on Tuesday July 20, 2021 @03:19PM (#27897988)
>> there are often times where it makes sense to use the platform's "natural" word sizes

In those cases we probably don't care about the full range of the larger types, so it doesn't hurt to use the smallest type for a range of expected values. If it does make a difference, the program will behave differently when compiled on a different arch or even a different compiler.

But maybe "generally" instead of "always". OTOH even I am guilty of using an int to loop over an array.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by cesarb on Tuesday July 20, 2021 @01:56PM (#27896975)
> This wouldn't be a problem if "int" was defined as the same size as size_t.

That would lead to a hole in the type sequence (char <= short <= int <= long <= long long) for 64-bit targets (where int is the 32-bit type while size_t is 64 bits).

> IMHO one should always be using C99 types instead of int, but Linux predates that.

On the other hand, on Linux "long" has always been defined as the same size as size_t, so using "long" instead of "int" everywhere could also be an option.

Re:size_t-to-int vulnerability in Linux’s filesystem layer by kenniskrag on Tuesday July 20, 2021 @01:40PM (#27896748)
so you mean int_fastX_t or int_leastX_t?
Re:size_t-to-int vulnerability in Linux’s filesystem layer by marcosdumay on Tuesday July 20, 2021 @05:21PM (#27899526)
I think Rust has no language construction for that, but the best implementation of "size as i32" should fail on overflow.

In Haskell I would use an exception, and mark the function as unsafe, but the stdlib seems to disagree with me here.