How defined is Rust?

Florob

Scope

Undefined behaviour How defined is Rust?

Arithmetic

Conversions Florian “Florob” Zeitz

Questions

2019-08-07

1 / 39 How defined is Rust?

Florob 1 Scope Scope

Undefined behaviour 2 Undefined behaviour Arithmetic Conversions 3 Arithmetic Aliasing

Questions 4 Conversions

5 Aliasing

2 / 39 How defined is Rust?

Florob 1 Scope Scope

Undefined behaviour 2 Undefined behaviour Arithmetic Conversions 3 Arithmetic Aliasing

Questions 4 Conversions

5 Aliasing

3 / 39 Previously

How defined is Rust?

Florob

Scope this talk is based around an older one “What you thought you knew

Undefined about ” behaviour stripped down the C parts Arithmetic Conversions added Rust’s perspective Aliasing not meant to be C bashing/zealotry Questions if you care about C look on media.ccc.de: sigint12 (english) CCCAC 2015 (german)

4 / 39 Disclaimer: What are we talking about?

How defined is Rust?

Florob

Scope

Undefined behaviour and/or C11 Arithmetic not necessarily C++ Conversions but Objective-C, as it works as a real superset Aliasing Questions Rust as of today (many things still being discussed)

5 / 39 How defined is Rust?

Florob 1 Scope Scope

Undefined behaviour 2 Undefined behaviour Arithmetic Conversions 3 Arithmetic Aliasing

Questions 4 Conversions

5 Aliasing

6 / 39 unspecified behaviour more than one possibility (e. g. evaluation of function arguments)

undefined behaviour everything goes, input program is considered erroneous (e. g. use-after-free)

What’s this?

How defined is Rust? Multiple types of “behaviour”: Florob

Scope implementation-defined behaviour

Undefined behaviour documented implementation choice (e. g. signedness of char)

Arithmetic

Conversions

Aliasing

Questions

7 / 39 undefined behaviour everything goes, input program is considered erroneous (e. g. use-after-free)

What’s this?

How defined is Rust? Multiple types of “behaviour”: Florob

Scope implementation-defined behaviour

Undefined behaviour documented implementation choice (e. g. signedness of char)

Arithmetic Conversions unspecified behaviour Aliasing

Questions more than one possibility (e. g. evaluation of function arguments)

7 / 39 What’s this?

How defined is Rust? Multiple types of “behaviour”: Florob

Scope implementation-defined behaviour

Undefined behaviour documented implementation choice (e. g. signedness of char)

Arithmetic Conversions unspecified behaviour Aliasing

Questions more than one possibility (e. g. evaluation of function arguments)

undefined behaviour everything goes, input program is considered erroneous (e. g. use-after-free)

7 / 39 this is (usually) not how things work compilers never look for optimizations work under the assumption there is no undefined behavior we’ll see some examples

The “evil compiler (writers)”

How defined is Rust? Florob the compiler looks for undefined behavior to subsequently break Scope your code Undefined behaviour all in the name of faster benchmarks Arithmetic don’t care about normal users, just numbers Conversions

Aliasing

Questions

8 / 39 The “evil compiler (writers)”

How defined is Rust? Florob the compiler looks for undefined behavior to subsequently break Scope your code Undefined behaviour all in the name of faster benchmarks Arithmetic don’t care about normal users, just numbers Conversions

Aliasing this is (usually) not how things work Questions compilers never look for undefined behavior optimizations work under the assumption there is no undefined behavior we’ll see some examples

8 / 39 How defined is Rust? What does this snippet usually print? Florob (optimized)

Scope 1 int a, b; Undefined 2 if (a) { behaviour 3 a = 3; Arithmetic 4 } else { Conversions 5 b = 4; Aliasing 6 } Questions 7 printf("%i\n", a + b); 3 4

5 7

9 / 39 How defined is Rust? What does this snippet usually print? Florob (optimized)

Scope 1 int a, b; Undefined 2 if (a) { behaviour 3 a = 3; Arithmetic 4 } else { Conversions 5 b = 4; Aliasing 6 } Questions 7 printf("%i\n", a + b); 3 4

5 7

9 / 39 Uninitialized in safe Rust

How defined is Rust?

Florob

Scope

Undefined behaviour Arithmetic Impossible in safe Rust Conversions compiler forbids usage of possibly uninitialized variables Aliasing

Questions

10 / 39 Uninitialized in unsafe Rust

How defined is Rust? 1 fn main() { Florob 2 let mut a = MaybeUninit::::uninit(); 3 let mut b = MaybeUninit::::uninit(); Scope 4 Undefined behaviour 5 if std::env::var("A").is_ok() { Arithmetic 6 unsafe { a.as_mut_ptr().write(3) };

Conversions 7 } else {

Aliasing 8 unsafe { b.as_mut_ptr().write(4) };

Questions 9 } 10 11 println!( 12 "{}", 13 unsafe { a.assume_init() + b.assume_init() } 14 ); 15 }

11 / 39 How defined is Rust?

Florob 1 Scope Scope

Undefined behaviour 2 Undefined behaviour Arithmetic Conversions 3 Arithmetic Aliasing

Questions 4 Conversions

5 Aliasing

12 / 39 How defined is Rust? What does this snippet usually print when size is INT_MAX? Florob (Optimized with -O3)

Scope 1 int size = ...; Undefined 2 if (size > size+1){ behaviour 3 puts("Aborted") Arithmetic 4 abort(); Conversions 5 } Aliasing 6 puts("Fetching memory"); Questions 7 malloc(size+1); Nothing ”Aborted”

”Fetching memory” size

13 / 39 How defined is Rust? What does this snippet usually print when size is INT_MAX? Florob (Optimized with -O3)

Scope 1 int size = ...; Undefined 2 if (size > size+1){ behaviour 3 puts("Aborted") Arithmetic 4 abort(); Conversions 5 } Aliasing 6 puts("Fetching memory"); Questions 7 malloc(size+1); Nothing ”Aborted”

”Fetching memory” size

13 / 39 Signed integer overflow (C)

How defined is Rust?

Florob

Scope

Undefined behaviour unsigned integer overflow is well-defined: UINT_MAX + 1 == 0 Arithmetic signed integer overflow is not: INT_MAX + 1 == /* undef */ Conversions rumours aside is not Aliasing INT_MAX + 1 INT_MIN Questions Check equality against INT_MAX

14 / 39 How defined is Rust? Florob 1 int size = ...; 2 if (size > size+1){ Scope 3 puts("Aborted") Undefined behaviour 4 abort();

Arithmetic 5 } 6 Conversions puts("Fetching memory"); 7 Aliasing malloc(size+1);

Questions Only defined behavior is considered size > size + 1 is always false Optimization removes the branch

15 / 39 Signed integer overflow (Rust)

How defined is Rust?

Florob

Scope same behaviour for all integer types, signed and unsigned Undefined behaviour debug: panic on overflow Arithmetic release: wrap around on overflow Conversions individual methods for specific requirements: Aliasing checked_add() Questions saturating_add() wrapping_add() overflowing_add()

16 / 39 How defined is Rust?

Florob What does this snippet usually print? (Unoptimized, on an x86 system) Scope 1 Undefined uint32_t shifty = 1; behaviour 2 shifty = shifty << 32; Arithmetic 3 printf("%"PRIu32"\n", shifty); Conversions

Aliasing

Questions 0 1

42 neither

17 / 39 How defined is Rust?

Florob What does this snippet usually print? (Unoptimized, on an x86 system) Scope 1 Undefined uint32_t shifty = 1; behaviour 2 shifty = shifty << 32; Arithmetic 3 printf("%"PRIu32"\n", shifty); Conversions

Aliasing

Questions 0 1

42 neither

17 / 39 Oversized shift amounts (C)

How defined is Rust?

Florob

Scope

Undefined If the value of the right operand is negative or is greater than or behaviour equal to the width of the promoted left operand, the behavior is Arithmetic undefined. Conversions Aliasing set variables to zero instead Questions easily checked when type width is known

18 / 39 Oversized shift amounts (Rust)

How defined is Rust?

Florob

Scope

Undefined debug: panic on oversized shift amount behaviour

Arithmetic release: mask right operand to bit width

Conversions individual methods for specific requirements: Aliasing checked_shl() Questions wrapping_shl() overflowing_shl()

19 / 39 How defined is Rust?

Florob 1 Scope Scope

Undefined behaviour 2 Undefined behaviour Arithmetic Conversions 3 Arithmetic Aliasing

Questions 4 Conversions

5 Aliasing

20 / 39 How defined is Rust? What does this snippet usually print? Florob (Optimized, clang or gcc) Scope 1 signed int s = -1; Undefined behaviour 2 unsigned int u = 1;

Arithmetic 3 if (s < u)

Conversions 4 puts("True");

Aliasing 5 else 6 Questions puts("False"); ”True” Nothing

”False” ”Trlse”

21 / 39 How defined is Rust? What does this snippet usually print? Florob (Optimized, clang or gcc) Scope 1 signed int s = -1; Undefined behaviour 2 unsigned int u = 1;

Arithmetic 3 if (s < u)

Conversions 4 puts("True");

Aliasing 5 else 6 Questions puts("False"); ”True” Nothing

”False” ”Trlse”

21 / 39 How defined is Rust?

Florob What does this snippet print?

1 Scope unsigned int u = 1; 2 Undefined signed int s1 = -2; behaviour 3 signed int s2 = u + s1; Arithmetic 4 printf("%i\n", s2); Conversions

Aliasing

Questions -1 0

4294967295 1

22 / 39 How defined is Rust?

Florob What does this snippet print?

1 Scope unsigned int u = 1; 2 Undefined signed int s1 = -2; behaviour 3 signed int s2 = u + s1; Arithmetic 4 printf("%i\n", s2); Conversions

Aliasing

Questions -1 0

4294967295 1

22 / 39 Usual arithmetic conversions

How defined is Rust?

Florob

Scope Applied for certain operations: Undefined multiplicative (*, /, %) behaviour Arithmetic additive (+, -) Conversions relational (<, >, <=, >=) Aliasing equality (==, !=) Questions bitwise (&, |, ^) conditional (a ? b : c, only to the second and third operand)

23 / 39 Usual arithmetic conversions - Example

How defined is Rust?

Florob

Scope 1 unsigned int a = 1; Undefined 2 signed int b = -1, c = a + b; behaviour 3 if (a > b) printf("True\n"); Arithmetic Conversions a and b have the same rank Aliasing For both + and >, b is converted to unsigned int Questions Effect: a > b is false

a + bsigned ≡ a + bunsigned (mod (UINT_MAX + 1)), hence a + b is 0

24 / 39 The problem

How defined is Rust?

Florob

Scope

Undefined behaviour depends on whom you ask Arithmetic

Conversions the rules for integer promotions and usual arithmetic conversions Aliasing having implicit conversions at all (cf. problems in JavaScript) Questions

25 / 39 Coercions and Rust

How defined is Rust?

Florob

Scope

Undefined behaviour Arithmetic Rust has almost no coercions Conversions those that exist are between lifetimes not types Aliasing

Questions

26 / 39 How defined is Rust?

Florob 1 Scope Scope

Undefined behaviour 2 Undefined behaviour Arithmetic Conversions 3 Arithmetic Aliasing

Questions 4 Conversions

5 Aliasing

27 / 39 How defined is Rust? What does this snippet usually print? Florob (Optimized, clang or gcc)

Scope

Undefined 1 void f(int *i, float *f) { 6 int main(void){ behaviour 2 *i = 42; 7 int var; Arithmetic 3 *f = 13; 8 f(&var, &var); Conversions 4 printf("%i\n", *i); 9 return 0; Aliasing 5 } 10 } Questions

42 13

0 1095761920

28 / 39 How defined is Rust? What does this snippet usually print? Florob (Optimized, clang or gcc)

Scope

Undefined 1 void f(int *i, float *f) { 6 int main(void){ behaviour 2 *i = 42; 7 int var; Arithmetic 3 *f = 13; 8 f(&var, &var); Conversions 4 printf("%i\n", *i); 9 return 0; Aliasing 5 } 10 } Questions

42 13

0 1095761920

28 / 39 Strict Aliasing Rule

How defined is Rust?

Florob

Scope C allows aliasing Undefined behaviour int *pa = &a, *pa aliases a Arithmetic not all expressions may be used to access an object Conversions

Aliasing expression and object type must match Questions this restriction is commonly called the strict aliasing rule with a declared as a float, *pa may be neither read nor written

29 / 39 Exceptions

How defined is Rust?

Florob

Scope Undefined different signedness behaviour

Arithmetic different qualifiers Conversions struct, array or with a member of one of the Aliasing aforementioned types Questions character type

30 / 39 Why have this rule?

How defined is Rust?

Florob

Scope

Undefined behaviour makes it harder to create trap/hiche values Arithmetic

Conversions avoids unaligned writes Aliasing restricts aliasing (potential for optimizations) Questions

31 / 39 (Strict) Aliasing and Rust

How defined is Rust?

Florob type punning is not possible in safe Rust Scope

Undefined generally Rust’s mutability XOR aliasing system gives stronger behaviour guarantees than this rule Arithmetic

Conversions arbitrary aliasing is possible in unsafe Rust Aliasing discussion is focussing more on maintaining mutability XOR aliasing Questions and provenance maybe we don’t need (purely) type based aliasing rules in Rust? certainly not for optimization

32 / 39 How defined is Rust? How many possible results does this function have? Florob 1 int f(signed int *i1, unsigned int *i2, float *f, char *c) { Scope 2 *i1 = 42; Undefined 3 *i2 = 43; behaviour 4 *f = 13.; Arithmetic 5 *c = 1; Conversions 6 return *i1 + *i2 + *f + *c; Aliasing 7 } Questions

19 1

2104 214

33 / 39 How defined is Rust? How many possible results does this function have? Florob 1 int f(signed int *i1, unsigned int *i2, float *f, char *c) { Scope 2 *i1 = 42; Undefined 3 *i2 = 43; behaviour 4 *f = 13.; Arithmetic 5 *c = 1; Conversions 6 return *i1 + *i2 + *f + *c; Aliasing 7 } Questions

19 1

2104 214

33 / 39 How defined is Rust? Florob 1 int f(signed int *i1, 1 .LCPI0_0: 2 unsigned int *i2, 2 .long 1065353216 # float 1 Scope 3 float *f, 3 f: Undefined behaviour 4 char *c) 4 movl $42,(%rdi) Arithmetic 5 { 5 movl $43,(%rsi) Conversions 6 *i1 = 42; 6 movl $1095761920,(%rdx)

Aliasing 7 *i2 = 43; 7 movb $1,(%rcx)

Questions 8 *f = 13.; 8 movl (%rsi), %eax 9 *c = 1; 9 addl (%rdi), %eax 10 return *i1 + *i2 + *f + *c; 10 cvtsi2ssq %rax, %xmm0 11 } 11 addss (%rdx), %xmm0 12 addss .LCPI0_0(%rip), %xmm0 13 cvttss2si %xmm0, %eax 14 retq

34 / 39 restrict

How defined is Rust?

Florob

Scope Undefined C99 added the restrict qualifier behaviour

Arithmetic can only be applied to pointer types Conversions the pointee may only be accessed via an expression based on the Aliasing pointer Questions restricts aliasing

35 / 39 How defined is Rust?

Florob

Scope 1 int f(signed int *restrict i1, 1 f: 2 2 Undefined unsigned int *restrict i2, movl $42,(%rdi) behaviour 3 float *restrict f, 3 movl $43,(%rsi) Arithmetic 4 char *restrict c) 4 movl $1095761920,(%rdx) Conversions 5 { 5 movb $1,(%rcx) Aliasing 6 *i1 = 42; 6 movl $99, %eax Questions 7 *i2 = 43; 7 retq 8 *f = 13.; 9 *c = 1; 10 return *i1 + *i2 + *f + *c; 11 }

36 / 39 &mut T

How defined is Rust?

Florob

Scope

Undefined behaviour Rust’s &mut T has stronger guarantees then restrict Arithmetic

Conversions no access via any other reference Aliasing enables even more optimizations Questions

37 / 39 &mut T

How defined is Rust?

Florob 1 fn f( 1 f: Scope 2 i1: &mut i32, i2: &mut u32, 2 movl $42,(%rdi) Undefined 3 f: &mut f32, c: &mut i8, 3 movl $43,(%rsi) behaviour 4 ) -> i32 { 4 movl $1095761920,(%rdx) Arithmetic 5 *i1 = 42; 5 movb $1,(%rcx) Conversions 6 *i2 = 43; 6 cvtsi2ssl (%rdi), %xmm0 Aliasing 7 *f = 13.; 7 movl (%rsi), %eax Questions 8 *c = 1; 8 cvtsi2ssq %rax, %xmm1 9 ( 9 addss %xmm0, %xmm1 10 *i1 as f32 + *i2 as f32 10 addss (%rdx), %xmm1 11 + *f + *c as f32 11 addss .LCPI4_0(%rip), %xmm1 12 ) as i32 12 cvttss2si %xmm1, %eax 13 } 13 retq

38 / 39 How defined is Rust? Florob Thank you for your attention.

Scope Any questions?

Undefined behaviour

Arithmetic

Conversions

Aliasing

Questions

https://babelmonkeys.de/~florob/talks/RC-2019-08-07-rust-defined.pdf

39 / 39