What is the undefined behaviour?

It works. Thanks.

Before that, I tried just use raw pointer as in C. Like:

use std::{collections::HashMap, hash::Hash, io::Write};

struct Key(* const [u8]);
impl Hash for Key {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        unsafe {
            (*self.0).hash(state);
        }
    }
}
impl PartialEq for Key {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            *self.0 == *other.0
        }
    }    
}
impl Eq for Key {}

struct Val(* mut [u8; 4]);


fn parse(data: &mut [u8]) -> Result<HashMap<Key, Val>, &'static str> {
    let mut map = HashMap::<Key, Val>::new();
    let mut cursor = 0;
    while !data.is_empty() {
        let mut key_len = 0;
        while data[cursor + key_len] != 0 && cursor + key_len < data.len() {
            key_len += 1;
        }
        if cursor + key_len + 5 > data.len() {
            return Err("Not enough data for value");
        }
        let key = Key(&data[cursor..cursor + key_len]);
        let val = Val(&mut (&mut data[cursor + key_len + 1..cursor + key_len + 5]).try_into().unwrap());
        map.insert(key, val);
        cursor += key_len + 5;
    }
    Ok(map)
}

fn main() {
    let mut data = vec![];
    data.write(b"key1").unwrap();
    data.write(&[0]).unwrap();
    data.write(&24_u32.to_be_bytes()).unwrap();
    data.write(b"key2").unwrap();
    data.write(&[0]).unwrap();
    data.write(&42_u32.to_be_bytes()).unwrap();
    let _ = parse(&mut data).unwrap();
    // println!("Value1: {}", u32::from_be_bytes(*parsed["key1".as_bytes()]));
    // println!("Value2: {}", u32::from_be_bytes(*parsed["key2".as_bytes()]));
}

And miri compains when I dereference the raw pointer.

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `/home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/play`
warning: field `0` is never read
  --> src/main.rs:20:12
   |
20 | struct Val(* mut [u8; 4]);
   |        --- ^^^^^^^^^^^^^
   |        |
   |        field in this struct
   |
   = note: `#[warn(dead_code)]` on by default
help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
   |
20 | struct Val(());
   |            ~~

error: Undefined Behavior: trying to retag from <3017> for SharedReadOnly permission at alloc1089[0x0], but that tag does not exist in the borrow stack for this location
  --> src/main.rs:7:13
   |
7  |             (*self.0).hash(state);
   |             ^^^^^^^^^
   |             |
   |             trying to retag from <3017> for SharedReadOnly permission at alloc1089[0x0], but that tag does not exist in the borrow stack for this location
   |             this error occurs as part of retag at alloc1089[0x0..0x4]
   |
   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <3017> was created by a SharedReadOnly retag at offsets [0x0..0x4]
  --> src/main.rs:34:23
   |
34 |         let key = Key(&data[cursor..cursor + key_len]);
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: <3017> was later invalidated at offsets [0x0..0x12] by a Unique retag
  --> src/main.rs:35:34
   |
35 |         let val = Val(&mut (&mut data[cursor + key_len + 1..cursor + key_len + 5]).try_into().unwrap());
   |                                  ^^^^
   = note: BACKTRACE (of the first span):
   = note: inside `<Key as std::hash::Hash>::hash::<std::hash::DefaultHasher>` at src/main.rs:7:13: 7:22
   = note: inside `core::hash::impls::<impl std::hash::Hash for &Key>::hash::<std::hash::DefaultHasher>` at /home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/hash/mod.rs:941:13: 941:33
   = note: inside `<std::hash::RandomState as std::hash::BuildHasher>::hash_one::<&Key>` at /home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/hash/mod.rs:701:9: 701:28
   = note: inside `hashbrown::map::make_hash::<Key, std::hash::RandomState>` at /home/billy/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-2eab394af869c8a2/hashbrown-0.14.3/src/map.rs:262:5: 262:31
   = note: inside `hashbrown::map::HashMap::<Key, Val, std::hash::RandomState>::insert` at /home/billy/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-2eab394af869c8a2/hashbrown-0.14.3/src/map.rs:1752:20: 1752:61
   = note: inside `std::collections::HashMap::<Key, Val>::insert` at /home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/collections/hash/map.rs:1105:9: 1105:31
note: inside `parse`
  --> src/main.rs:36:9
   |
36 |         map.insert(key, val);
   |         ^^^^^^^^^^^^^^^^^^^^
note: inside `main`
  --> src/main.rs:50:13
   |
50 |     let _ = parse(&mut data).unwrap();
   |             ^^^^^^^^^^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error; 1 warning emitted

I wonder what is the root cause of this error. Isn't it true that raw pointers has no no-aliasing optimization?