Skip to content

Conversation

@leonardogiovannoni
Copy link

Description

I’m seeing a heap corruption crash when using glommio::channels::spsc_queue from multiple producer and consumer threads.

The code only uses safe Rust and the public glommio::channels::spsc_queue API, but at runtime it fails with:

Avvio demo Glommio Multi-Thread...
malloc(): chunk size mismatch in fastbin
malloc(): chunk size mismatch in fastbin
Aborted (core dumped) cargo run

This looks like memory corruption / unsoundness in safe code.

I realize this is an SPSC queue and that my sample intentionally uses multiple producers and multiple consumers, but since the API is fully safe, it shouldn’t be possible to trigger heap corruption (ideally the type system or runtime checks would prevent this usage, or at worst it should fail cleanly without UB).


Environment

  • Glommio version: 0.9.0 (from github)
  • Rust version: rustc 1.xx.x (stable)
  • OS: Linux x86_64 Fedora
  • Build: cargo run --release and cargo run both affected

Minimal reproducible example

use std::error::Error;
use glommio::channels::spsc_queue;

fn main() -> Result<(), Box<dyn Error>> {
    println!("Avvio demo Glommio Multi-Thread...");
    let (sender, mut receiver) = spsc_queue::make::<String>(4096);

    let mut producers = Vec::new();
    let mut consumers = Vec::new();

    // 2 producers
    for i in 0..2 {
        let sender = sender.clone();
        producers.push(std::thread::spawn(move || {
            for j in 0..500_000 {
                let msg = format!("Messaggio {} dal produttore {}\n", j, i);
                // ignoring the return value for simplicity
                let _ = sender.try_push(msg);
            }
        }));
    }

    // 2 consumers
    for _ in 0..2 {
        let receiver = receiver.clone();
        consumers.push(std::thread::spawn(move || {
            for _ in 0..500_000 {
                let _ = receiver.try_pop();
            }
        }));
    }

    for producer in producers {
        producer.join().unwrap();
    }
    for consumer in consumers {
        consumer.join().unwrap();
    }

    Ok(())
}

Running this with cargo run produces:

Avvio demo Glommio Multi-Thread...
malloc(): chunk size mismatch in fastbin
malloc(): chunk size mismatch in fastbin
Aborted (core dumped) cargo run

Expected behavior

Even if using spsc_queue in a way that violates its logical “single producer / single consumer” design, the use of safe APIs should not result in undefined behavior or heap corruption.

Ideally one of the following would happen instead:

  • The type system prevents this misuse (e.g. Producer / Consumer not being Clone, or being more constrained), or
  • There are documented guarantees that misusing the queue can cause UB, or
  • The queue detects this situation and fails in a defined way (panic, error, etc.), rather than corrupting memory.

Actual behavior

  • Program prints Avvio demo Glommio Multi-Thread...

  • Then glibc reports:

    malloc(): chunk size mismatch in fastbin
    malloc(): chunk size mismatch in fastbin
    Aborted (core dumped)
    
  • This suggests memory corruption happening internally, triggered only through safe Producer::try_push and Consumer::try_pop calls.


Additional notes

  • Producer<T> and Consumer<T> are Send but !Sync, and they are Clone. This allows creating multiple cloned producers/consumers that operate concurrently on the same underlying queue from different threads.
  • The module name spsc_queue suggests single-producer/single-consumer behavior, but the current API surface (especially Clone + Send) makes it easy to use it in multi-producer/multi-consumer scenarios without any compiler errors or warnings.
  • Even if this usage is considered invalid, the fact that it leads to heap corruption in safe Rust feels like at least a documentation or soundness issue.

If this usage is explicitly unsupported and considered undefined behavior, it might be helpful to:

  1. Clarify that in the documentation for spsc_queue::make, Producer, and Consumer, and/or
  2. Tighten the API (e.g. remove Clone or add runtime checks) so that this pattern doesn’t compile or at least doesn’t lead to memory corruption.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant