summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/src/docs/cast_slice_different_sizes.txt
blob: c01ef0ba92c03d0c66381a52e5506f7b9bfddeec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
### What it does
Checks for `as` casts between raw pointers to slices with differently sized elements.

### Why is this bad?
The produced raw pointer to a slice does not update its length metadata. The produced
pointer will point to a different number of bytes than the original pointer because the
length metadata of a raw slice pointer is in elements rather than bytes.
Producing a slice reference from the raw pointer will either create a slice with
less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.

### Example
// Missing data
```
let a = [1_i32, 2, 3, 4];
let p = &a as *const [i32] as *const [u8];
unsafe {
    println!("{:?}", &*p);
}
```
// Undefined Behavior (note: also potential alignment issues)
```
let a = [1_u8, 2, 3, 4];
let p = &a as *const [u8] as *const [u32];
unsafe {
    println!("{:?}", &*p);
}
```
Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
```
let a = [1_i32, 2, 3, 4];
let old_ptr = &a as *const [i32];
// The data pointer is cast to a pointer to the target `u8` not `[u8]`
// The length comes from the known length of 4 i32s times the 4 bytes per i32
let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
unsafe {
    println!("{:?}", &*new_ptr);
}
```