Stack overflow with mpsc try_recv() in a thread pool

I get a stack overflow exactly when calling try_recv() no matter how many elements in the queue

use std::thread;
use std::thread::JoinHandle;
use std::time;
use crossbeam::channel::bounded;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use cgmath::Vector3;
use crate::chunk::Chunk;
use std::sync::mpsc::*;
use std::time::Duration;

pub struct ChunkLoader{
    sender_pos:crossbeam::channel::Sender<Vector3<i32>>,
    receiver_chunk:Receiver<(Vector3<i32>,Chunk)>,
    thread_handles:Vec<JoinHandle<()>>,
    running:Arc<AtomicBool>
}
impl ChunkLoader{
    pub fn new()->Self{
        let (sender_pos,receiver_pos) = bounded(10);
        let (sender_chunk,receiver_chunk)=channel();
        let mut thread_handles=Vec::new();
        let running = Arc::new(AtomicBool::new(true));
        for i in 0..4{
            let loc_receiver_pos = receiver_pos.clone();
            let loc_sender_chunk= sender_chunk.clone();
            let loc_running= running.clone();
            thread_handles.push(thread::spawn(move || {
                while loc_running.load(Ordering::Relaxed) {
                    thread::sleep(Duration::from_millis(20));
                    let pos = loc_receiver_pos.try_recv();
                    match pos{
                        Ok(chunk_pos)=>{
                            loc_sender_chunk.send((chunk_pos,Chunk::new(chunk_pos))).unwrap();
                        }
                        Err(_)=>{}
                    }

                }
            }));
        }
        ChunkLoader{
            sender_pos,
            receiver_chunk,
            thread_handles,
            running
        }
    }
    pub fn load(&self,pos:Vector3<i32>){
        self.sender_pos.send(pos).unwrap();
    }
    pub fn try_get_chunk(&self) -> Result<(Vector3<i32>, Chunk), TryRecvError> {
        println!("stack overflow here");
        let result=self.receiver_chunk.try_recv();
        println!("not reached");
        result
    }
}
impl Drop for ChunkLoader {
    fn drop(&mut self) {
        self.running.store(false,Ordering::Relaxed);
        for i in 0..4{
            self.thread_handles.remove(0).join().unwrap();
        }
    }
}

You've probably got infinite recursion somewhere, but I can't tell you where because the snippet you posted doesn't compile (the chunk module is elsewhere and there is no main() function or test to run).

Some general tips:

  • Run your code inside a debugger (e.g. gdb) - it should automatically break when the stack overflow is triggered, allowing you to print a backtrace and see where the unbounded recursion is
  • Simplify your code by commenting bits out until the stack overflow goes away - this should give you an idea of which line triggers the stack overflow
  • Make sure you aren't putting massive buffers on the stack - in a WebAssembly application at work I was originally storing tensors as arrays on the stack and the code would segfault when working with larger tensors. After some debugging I found that we'd told wasmer to reduce the stack size and just storing a couple of those arrays in local variables put us over
  • The naive linked list implementation can overflow the stack when it gets dropped because each Node<T> holds an Option<Box<Node<T>>>, meaning when you drop a node the drop glue generated by the compiler will also recursively drop its child. This recursion will blow the stack if the list is too big and may be what you are seeing if Chunk is a form of linked list
  • Try to create a Minimal, Reproducible Example on the playground (preferred) or upload it to a GitHub repo - it's hard to troubleshoot something when you don't have all the code or need to read through hundreds of lines
1 Like

So i found it was due to my Chunk class,who has a 65536 byte(323232*2) array,so I boxed my class ,I didn't wanted to copy all theses bytes anyway
But I'm still surprised,because this happen even if I did not sent any chunk,not even a chunk initialized,and with 65kb you still need a few of them to eat all the stack