Search code examples
rustraylib

STATUS_HEAP_CORRUPTION in rust code using raylib bindings


My problem code is as follows:

use raylib::prelude::*;
use std::{
    f32::consts::PI,
    os::raw::c_void,
    path::Path,
    sync::{Arc, Mutex},
    thread,
};

mod wave;

fn export_wave(slider_positions: [f32; 8]) {
    let path: &Path = Path::new("test.wav");
    let mut data: Vec<f32> = vec![];
    let mut x: f32 = 0.0;
    while x < 10.0 {
        let sample: f32 = slider_to_sample(x, slider_positions[0], 0.0, 1000.0)
            + slider_to_sample(x, slider_positions[1], 0.0, 1000.0)
            + slider_to_sample(x, slider_positions[2], 0.0, 1000.0)
            + slider_to_sample(x, slider_positions[3], 0.0, 1000.0)
            + slider_to_sample(x, slider_positions[4], 0.0, 1000.0)
            + slider_to_sample(x, slider_positions[5], 0.0, 1000.0)
            + slider_to_sample(x, slider_positions[6], 0.0, 1000.0)
            + slider_to_sample(x, slider_positions[7], 0.0, 1000.0);
        let _ = data.insert(data.len(), sample);
        x += 1.0/44100;
    }

    wave::make_wave_file(
        path,
        WAVE {
            data,
            format: wave::IEEE_754_FLOAT,
            num_channels: 1,
            sample_rate: 44100,
        },
    );
}

fn slider_to_sample(x: f32, position: f32, min: f32, max: f32) -> f32 {
    f32::sin(x * ((1.0 - position) * max + min) * PI)
}

#[derive(Clone, Debug)]
struct AudioInfo {
    slider_positions: [f32; 8],
    playing: bool,
    close: bool,
}

impl AudioInfo {
    fn new() -> Self {
        AudioInfo {
            slider_positions: [1.0; 8],
            playing: false,
            close: false,
        }
    }
}

fn get_sound(audio_info: AudioInfo) -> Sound {
    let mut data: [f32; 44100] = [0.0; 44100];
    let mut x: f32 = 0.0;
    for i in 0..44100 {
        data[i] = slider_to_sample(x, audio_info.slider_positions[0], 0.0, 1000.0)
            + slider_to_sample(x, audio_info.slider_positions[1], 0.0, 1000.0)
            + slider_to_sample(x, audio_info.slider_positions[2], 0.0, 1000.0)
            + slider_to_sample(x, audio_info.slider_positions[3], 0.0, 1000.0)
            + slider_to_sample(x, audio_info.slider_positions[4], 0.0, 1000.0)
            + slider_to_sample(x, audio_info.slider_positions[5], 0.0, 1000.0)
            + slider_to_sample(x, audio_info.slider_positions[6], 0.0, 1000.0)
            + slider_to_sample(x, audio_info.slider_positions[7], 0.0, 1000.0);
        x += 1.0 / 44100.0;
    }

    let wave_ptr: *mut c_void = &mut data as *mut _ as *mut c_void;
    
    let wave: ffi::Wave = ffi::Wave {
        sampleCount: 44100,
        sampleRate: 44100,
        sampleSize: 32,
        channels: 1,
        data: wave_ptr,
    };
    
    return Sound::load_sound_from_wave(unsafe { &Wave::from_raw(wave) }).unwrap();
}

fn main() {
    let (mut rl, thread) = raylib::init().size(640, 480).title("Hello, World").build();

    let audio_info: Arc<Mutex<AudioInfo>> = Arc::new(Mutex::new(AudioInfo::new()));

    let audio_thread: thread::JoinHandle<()>;
    {
        let audio_info: Arc<Mutex<AudioInfo>> = Arc::clone(&audio_info);
        audio_thread = thread::spawn(move || {
            use raylib::audio::*;
            let mut rl_audio: RaylibAudio = RaylibAudio::init_audio_device();
            let mut sound: Sound = get_sound((*audio_info.lock().unwrap()).clone());
            
            while !audio_info.lock().unwrap().close {
                if rl_audio.get_sounds_playing() == 0 {
                    rl_audio.play_sound_multi(&sound)
                } else {
                    get_sound((*audio_info.lock().unwrap()).clone());
                }
            }
        })
    };

    while !rl.window_should_close() {
        /* gui loop */
    }

    audio_info.lock().unwrap().close = true;
    let _ = audio_thread.join();
}

Using raylib = "3.7.0"

When executing my code, it returns exit code 0xC0000374, STATUS_HEAP_CORRUPTION. I was able to track it down to line 91 at the end of get_sound using println. I don't know much more about the problem beyond that. I can post the rest of main if necessary but it does not interact with the audio thread.


Solution

  • I believe Wave (not the ffi one) will try to release memory on drop, but since the underlying pointer is to your data variable on the stack that isn't going to work. I can't see a way to do this in a cleaner way, so I would do this:

    let wave2 = unsafe { Wave::from_raw(wave) };
    let sound = Sound::load_sound_from_wave(&wave2).unwrap();
    std::mem::forget(wave2);
    
    return sound;