roc: `Num.intCast` enables segfaults by blessing negative `Nat`s
This is the root cause of https://github.com/rtfeldman/roc/issues/3377.
Here is an example of Num.intCast enabling a negative list capacity, which the REPL accepts:
» List.withCapacity -100
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
The 1st argument to withCapacity is not what I expect:
4│ List.withCapacity -100
^^^^
This argument is a number of type:
I8, I16, I32, I64, I128, F32, F64, or Dec
But withCapacity needs the 1st argument to be:
Nat
» List.withCapacity (Num.intCast -100)
[] : List a
» List.withCapacity (Num.intCast -100) |> List.sum |> Num.toStr
"0" : Str
»
Here is an example of a compiled app rejecting the same negative list capacity:
[jan@framey roc]$ cat withoutIntCast.roc
app "test"
packages { pf: "examples/hello-world/platform/main.roc" }
imports []
provides [main] to pf
main = List.withCapacity -100 |> List.sum |> Num.toStr
[jan@framey roc]$
[jan@framey roc]$
[jan@framey roc]$ cargo run withoutIntCast.roc
Finished dev [unoptimized + debuginfo] target(s) in 0.40s
Running `target/debug/roc withoutIntCast.roc`
🔨 Rebuilding host...
── TYPE MISMATCH ────────────────────────────────────────── withoutIntCast.roc ─
The 1st argument to withCapacity is not what I expect:
6│ main = List.withCapacity -100 |> List.sum |> Num.toStr
^^^^
This argument is a number of type:
I8, I16, I32, I64, I128, F32, F64, or Dec
But withCapacity needs the 1st argument to be:
Nat
────────────────────────────────────────────────────────────────────────────────
1 error and 0 warnings found in 582 ms.
You can run the program anyway with: roc run withoutIntCast.roc
[jan@framey roc]$
[jan@framey roc]$
[jan@framey roc]$ cat withIntCast.roc
app "test"
packages { pf: "examples/hello-world/platform/main.roc" }
imports []
provides [main] to pf
main = List.withCapacity (Num.intCast -100) |> List.sum |> Num.toStr
[jan@framey roc]$
[jan@framey roc]$
[jan@framey roc]$ cargo run withIntCast.roc
Finished dev [unoptimized + debuginfo] target(s) in 0.40s
Running `target/debug/roc withIntCast.roc`
🔨 Rebuilding host...
Segmentation fault (core dumped)
[jan@framey roc]$
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 16 (5 by maintainers)
Can we split this into two issues?
One about
Num.intCastbeing unintuitive to new users and one about allocating giant amounts of memory (and if roc should do anything about it)?🤔 Actually, the problem also occurs when calling
Here,
18446744073709551614is definitely a validNat. So this can be considered a separate problem fromNum.intCast. But internally inside the implementation ofList.withCapacity, this very large unsigned number it is turned back into (or probably more accurately ‘reinterpreted as’) a signed number.🤔 What about adding a
debug_assert? That way, we will be able to debug problems related to it more quickly when doing tests on a debug build, while not slowing down production code.