mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 08:38:09 -05:00
Save a draft of insane allocators post
This commit is contained in:
parent
6195e13734
commit
68fe294327
71
_posts/2019-02-14-insane-allocators.md
Normal file
71
_posts/2019-02-14-insane-allocators.md
Normal file
@ -0,0 +1,71 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Insane Allocators: SEGFAULTs in safe Rust"
|
||||
description: "\"Trusting trust\" with allocators."
|
||||
category: rust, memory
|
||||
tags: []
|
||||
---
|
||||
|
||||
Having recently spent a lot of time studying the weird ways that
|
||||
[Rust uses memory](/2019/02/understanding-allocations-in-rust.html),
|
||||
I like to think I finally understand the rules well enough to
|
||||
break them. Specifically - what are the assumptions that underpin
|
||||
Rust's memory model? It wasn't a question particularly relevant
|
||||
to understanding how Rust allocates memory, but is certainly worth
|
||||
discussing as an addendum. Let's finish off this series on Rust and
|
||||
memory by breaking the most important rules Rust has!
|
||||
|
||||
Rust's whole shtick is that it's "memory safe." In practice,
|
||||
this (should) mean that there's no undefined behavior in safe Rust,
|
||||
because the compiler/borrow checker makes sure you can't get yourself
|
||||
into a situation where you misuse or corrupt memory. But is it possible
|
||||
for Rust programs, *written without using `unsafe`*, to encounter a
|
||||
[segfault](https://en.wikipedia.org/wiki/Segmentation_fault)?
|
||||
|
||||
Of course it is! Using an unmodified compiler, I can build a simple
|
||||
"Hello, world!" application that dies due to memory corruption:
|
||||
|
||||
<script id="asciicast-ENIpRYpdDazCkppanf3LSCetX" src="https://asciinema.org/a/ENIpRYpdDazCkppanf3LSCetX.js" async></script>
|
||||
|
||||
# Wait, wat?
|
||||
|
||||
There's obviously something nefarious going on. I mean, why would
|
||||
anyone use `sudo` to run the `rustc` compiler?
|
||||
|
||||
And for that matter, why does Rust 1.31.0 behave differently
|
||||
from Rust 1.32.0?
|
||||
|
||||
To pull off this chicanery, I'm making use of a special environment
|
||||
variable in Linux called [`LD_PRELOAD`](https://blog.fpmurphy.com/2012/09/all-about-ld_preload.html).
|
||||
I won't go into detail the way [Matt Godbolt does](https://www.youtube.com/watch?v=dOfucXtyEsU),
|
||||
but the important bit is this: I can insert my own code in place of
|
||||
functions typically implemented by the [C standard library](https://www.gnu.org/software/libc/).
|
||||
|
||||
Second, there's a very special implementation of [`malloc`](https://linux.die.net/man/3/malloc)
|
||||
that is being picked up by `LD_PRELOAD`:
|
||||
|
||||
```rust
|
||||
use std::ffi::c_void;
|
||||
use std::ptr::null_mut;
|
||||
|
||||
// Start off with an empty pointer
|
||||
static mut ALLOC: *mut c_void = null_mut();
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn malloc(size: usize) -> *mut c_void {
|
||||
unsafe {
|
||||
// If we've never allocated anything, ask the operating system
|
||||
// for some memory...
|
||||
if ALLOC == null_mut() {
|
||||
ALLOC = libc::malloc(size)
|
||||
}
|
||||
// ...and then give that same section of memory to everyone,
|
||||
// corrupting the location.
|
||||
return ALLOC;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, there are two questions yet to answer:
|
||||
1. Why was `sudo` used to compile?
|
||||
2. Why did Rust 1.31 work when 1.32 didn't?
|
Loading…
Reference in New Issue
Block a user