roc-lang / roc

A fast, friendly, functional language.
https://roc-lang.org
Universal Permissive License v1.0
4.46k stars 314 forks source link

Undefined behavior for bitwise shifts at the exact integer size #6789

Open mpizenberg opened 5 months ago

mpizenberg commented 5 months ago
❯ roc --version
roc nightly pre-release, built from commit 010aed88f9d on Wed May  8 09:12:51 UTC 2024

I’m currently testing Roc on macos with an M3 chip. In these conditions, I’m observing some UB and panics. Here is the output of the repl for example (I’m changing white space for readability).

» Num.shiftRightZfBy 1_u128 128
0 : U128

» Num.shiftRightZfBy 1_u64 64
1 : U64

» Num.shiftRightZfBy 1_u32 32
0 : U32

» Num.shiftRightZfBy 1_u16 16
0 : U16

» Num.shiftRightZfBy 1_u8 8
0 : U8

» Num.shiftLeftBy 1_u8 8
0 : U8

» Num.shiftLeftBy 1_u16 16
0 : U16

» Num.shiftLeftBy 1_u32 32
0 : U32

» Num.shiftLeftBy 1_u64 64
1 : U64

» Num.shiftLeftBy 1_u128 128
thread 'main' panicked at crates/compiler/gen_dev/src/generic64/mod.rs:4711:48:
not yet implemented

The UB happens when the shift value corresponds to the integer size. Sometimes it returns 0, sometimes it returns the integer input unchanged.

Similar UB is also observed when compiling with roc test.

This problem was originally reported on zulip: https://roc.zulipchat.com/#narrow/stream/231634-beginners/topic/Bug.20with.20shiftRightZfBy.3F

During the discussion, @bhansconnect also mentioned Zig behavior, which limits the integer size of the shift to the integer size, instead of U8 for all integer types. For example, A shift on U32 numbers is done with a shift value of type U5.