How defined is Rust?
Florob
Scope
Undefined behaviour How defined is Rust?
Arithmetic
Conversions Florian “Florob” Zeitz Aliasing
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 C” 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 C99 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 undefined behavior 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::
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 union type 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