Discovering self-referential structs 229 Let's try to run our program and see what we get: Program starting FIRST POLL-START OPERATION main: 1 pending tasks. Sleep until notified. FIRST POLL-START OPERATION main: 1 pending tasks. Sleep until notified. /400/Hello Asyn free(): double free detected in tcache 2 Aborted Wait, what?!? That doesn't sound good! Okay, that's probably a kernel bug in Linux, so let's try it on Windows instead:... error: process didn't exit successfully: `target\release\c-coroutines-problem. exe` (exit code: 0xc0000374, STATUS_HEAP_CORRUPTION) That sounds even worse!! What happened here? Let's take a closer look at exactly what happened with our async system when we made our small optimization. Discovering self-referential structs What happened is that we created a self-referential struct, initialized it so that it took a pointer to itself, and then moved it. Let's take a closer look: 1. First, we received a future object as an argument to block_on. This is not a problem since the future isn't self-referential yet, so we can move it around wherever we want to without issues (this is also why moving futures before they're polled is perfectly fine using proper async/await). 2. Then, we polled the future once. The optimization we did made one essential change. The future was located on the stack (inside the stack frame of our block_on function) when we polled it the first time. 3. When we polled the future the first time, we initialized the variables to their initial state. Our writer variable took a pointer to our buffer variable (stored as a part of our coroutine) and made it self-referential at this point. 4. The first time we polled the future, it returned Not Ready 5. Since it returned Not Ready, we spawned the future, which moves it into the tasks collection with the Hash Map<usize, Box<dyn Future<Output = String>>> type in our Executor. The future is now placed in Box, which moves it to the heap.