Skip to content

Core trait misrepresents the lifetime of GameData #12

@stewbasic

Description

@stewbasic

A Core is able to access the GameData any time between on_load_game (when it is passed in) until on_unload_game (when it must be returned). However the data seems to be valid only for the duration of the on_load_game call (I don't know if the libretro documentation states this explicitly anywhere). Thus the trait allows use-after-free errors. Consider the following minimal example:

extern crate libretro_backend;

use libretro_backend::*;

const WIDTH: usize = 320;
const HEIGHT: usize = 240;

struct MyCore {
    video: Vec<u8>,
    game_data: Option<GameData>,
}

impl Default for MyCore {
    fn default() -> Self {
        let (video, game_data) = (vec![0x40; WIDTH * HEIGHT * 4], None);
        Self { video, game_data }
    }
}

impl MyCore {
    fn print(&self, label: &str) {
        if let Some(game_data) = &self.game_data {
            if let Some(data) = game_data.data() {
                println!("{}: {:?}", label, data);
            }
        }
    }
}

impl Core for MyCore {
    fn info() -> CoreInfo {
        CoreInfo::new("defect", "0.1").supports_roms_with_extension("txt")
    }
    fn on_load_game(&mut self, game_data: GameData) -> LoadGameResult {
        self.game_data = Some(game_data);
        self.print("on_load_game");
        let info =
            AudioVideoInfo::new().video(WIDTH as u32, HEIGHT as u32, 60.0, PixelFormat::ARGB8888);
        LoadGameResult::Success(info)
    }
    fn on_unload_game(&mut self) -> GameData {
        self.game_data.take().unwrap()
    }
    fn on_run(&mut self, handle: &mut RuntimeHandle) {
        self.print("run");
        handle.upload_video_frame(&self.video);
    }
    fn on_reset(&mut self) {}
}

libretro_core!(MyCore);

$ retroarch --version
RetroArch: Frontend for libretro -- v1.4.1 -- d8855ca --
$ echo blah > text.txt
$ retroarch -L target/release/libdefect.so text.txt 2>/dev/null
on_load_game: [98, 108, 97, 104, 10]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions