Boscop / web-view

Rust bindings for webview, a tiny cross-platform library to render web-based GUIs for desktop applications
MIT License
1.91k stars 173 forks source link

Malloc issues with webview #79

Open martinellison opened 4 years ago

martinellison commented 4 years ago

edit: the problem seems to be in the c library that this crate wraps. old edit: I have added an example program that demonstrates the bug in the first comment (also the standard examples also display the error when run under valgrind).

I've been getting malloc crashes which I think are associated with rust webview. The crashes only happen later during app cleanup but when I run my code under valgrind I get the following messages (excerpt only, but the rest is more of the same). The actual final crash is in the sqlite3 deallocation.

Context

Messages

main thread is ThreadId(1) main running engine with webview... main building webview... engine initial html took 0.024s ==9220== Warning: set address range perms: large range [0x59c04000, 0x999c04000) (defined) ==9220== Warning: set address range perms: large range [0x59c04000, 0x80000000) (noaccess) ==9220== Warning: set address range perms: large range [0x940000000, 0x999c04000) (noaccess) main webview built. main web view ready main running... ==9220== Thread 9 ReceiveQueue: ==9220== Syscall param sendmsg(msg.msg_iov[0]) points to uninitialised byte(s) ==9220== at 0x494C66C: sendmsg (sendmsg.c:28) ==9220== by 0x51D4EA7: ??? (in /usr/lib/aarch64-linux-gnu/libwebkit2gtk-4.0.so.37.37.6) ==9220== Address 0x1a9ff261 is on thread 9's stack ==9220== ==9220== Thread 1: ==9220== Invalid read of size 8 ==9220== at 0x170BDC: <std::sync::rwlock::RwLockWriteGuard as core::ops::drop::Drop>::drop (rwlock.rs:554) ==9220== by 0x172DF7: core::ptr::real_drop_in_place (mod.rs:197) ==9220== by 0x177C47: web_view::WebView::_into_inner (lib.rs:466) ==9220== by 0x177AB7: web_view::WebView::into_inner (lib.rs:448) ==9220== by 0x178167: web_view::WebView::run (lib.rs:440) ==9220== by 0x16C687: fanling10::run_engine_with_webview (main.rs:145) ==9220== by 0x16BCFB: fanling10::actual_main (main.rs:85) ==9220== by 0x16B4E3: fanling10::main (main.rs:56) ==9220== by 0x175407: std::rt::lang_start::{{closure}} (rt.rs:64) ==9220== by 0x79BDEB: {{closure}} (rt.rs:49) ==9220== by 0x79BDEB: std::panicking::try::do_call (panicking.rs:296) ==9220== by 0x7A10BB: __rust_maybe_catch_panic (lib.rs:82) ==9220== by 0x79C733: try<i32,closure> (panicking.rs:275) ==9220== by 0x79C733: catch_unwind<closure,i32> (panic.rs:394) ==9220== by 0x79C733: std::rt::lang_start_internal (rt.rs:48) ==9220== Address 0xcbdd930 is 16 bytes inside a block of size 32 free'd ==9220== at 0x4845D58: free (in /usr/lib/valgrind/vgpreload_memcheck-arm64-linux.so) ==9220== Block was alloc'd at ==9220== at 0x4844BFC: malloc (in /usr/lib/valgrind/vgpreload_memcheck-arm64-linux.so) ==9220== ==9220== Invalid write of size 1 ==9220== at 0x176130: std::sys::unix::rwlock::RWLock::write_unlock (rwlock.rs:115) ==9220== by 0x17152B: std::sys_common::rwlock::RWLock::write_unlock (rwlock.rs:64) ==9220== by 0x170BE3: <std::sync::rwlock::RwLockWriteGuard as core::ops::drop::Drop>::drop (rwlock.rs:554) ==9220== by 0x172DF7: core::ptr::real_drop_in_place (mod.rs:197) ==9220== by 0x177C47: web_view::WebView::_into_inner (lib.rs:466) ==9220== by 0x177AB7: web_view::WebView::into_inner (lib.rs:448) ==9220== by 0x178167: web_view::WebView::run (lib.rs:440) ==9220== by 0x16C687: fanling10::run_engine_with_webview (main.rs:145) ==9220== by 0x16BCFB: fanling10::actual_main (main.rs:85) ==9220== by 0x16B4E3: fanling10::main (main.rs:56) ==9220== by 0x175407: std::rt::lang_start::{{closure}} (rt.rs:64) ==9220== by 0x79BDEB: {{closure}} (rt.rs:49) ==9220== by 0x79BDEB: std::panicking::try::do_call (panicking.rs:296) ==9220== Address 0xcbdd8d0 is 64 bytes inside a block of size 72 free'd ==9220== at 0x4845D58: free (in /usr/lib/valgrind/vgpreload_memcheck-arm64-linux.so) ==9220== Block was alloc'd at ==9220== at 0x4844BFC: malloc (in /usr/lib/valgrind/vgpreload_memcheck-arm64-linux.so)

martinellison commented 4 years ago

Here is a reasonably short example that exhibits the behaviour that I have described in the original post. It is a simplified form of the code that generated the previous error. Also, I have added the Cargo.toml file. To display the bug, you can

Text of example

/*! Test of webview */
extern crate web_view;
use ansi_term::Colour::*;
use ansi_term::Style;
use std::path::PathBuf;
use std::thread;
use std::time::SystemTime;
use web_view::*;

#[macro_use]
extern crate quick_error;
quick_error! {
#[derive(Debug)]
/** Error found in test case */
pub enum WebviewTestError {
/// internal error
    WebviewTestError(msg: String) {from()}
    /// internal IO error
    Io(err: std::io::Error) {from() cause(err)   description(err.description())}
    /// webview error
Web(err: web_view::Error)  {from() cause(err)   description(err.description())}
/// system time error
Time(err:std::time::SystemTimeError) {from() cause(err)   description(err.description())}
}}

impl WebviewTestError {
    pub fn new(txt: &str) -> Self {
        Self::WebviewTestError(txt.to_string())
    }
}
type NullResult = Result<(), WebviewTestError>;

/** used by [web_view::WebView] */
struct UserData {}
impl Drop for UserData {
    fn drop(&mut self) {
        trace(Blue.on(White), "dropping userdata");
    }
}

fn main() {
    let mark = Mark::new();
    actual_main().expect("internal error");
    trace(Blue.on(White), "really ending main.");
    mark.touch();
}
fn actual_main() -> NullResult {
    trace(Blue.on(White), "starting main");
    trace(
        Blue.on(White),
        &format!("thread is {:?}", thread::current().id(),),
    );
    trace(Blue.on(White), "running with webview...");
    run_with_webview()?;
    trace(Blue.on(White), "finished running with webview");
    Ok(())
}
fn run_with_webview() -> NullResult {
    trace(Blue.on(White), "building webview...");
    let p = UserData {};
    {
        let now = SystemTime::now();
        let mut webview = web_view::builder()
            .title("Test")
            .content(web_view::Content::Html("hello webview"))
            .size(640, 960)
            .resizable(true)
            .debug(false)
            .user_data(p)
            .invoke_handler(invoke_handler)
            .build()?;
        trace(Blue.on(White), "webview built.");

        webview.set_color((156, 39, 176));
        trace(
            Black.on(White),
            &format!("web view ready, thread is {:?}", thread::current().id()),
        );
        trace(
            Blue.on(White),
            &format!(
                "building webview took {}s ",
                now.elapsed()?.as_millis() as f64 / 1000.0,
            ),
        );
        let _res = webview.run()?;
        trace(Blue.on(White), "run.");
    }

    trace(Blue.on(White), "run, ending main.");
    Ok(())
}
fn invoke_handler(webview: &mut WebView<UserData>, arg: &str) -> WVResult {
    trace(
        Black.on(White),
        &format!(
            "main handler, arg {}, thread is {:?}",
            arg,
            thread::current().id()
        ),
    );
    webview.set_title(&format!("Webview test"))?;
    let response = Ok(()); //webview.user_data_mut().engine.execute(arg);
    handle_response(webview, &response, arg);
    Ok(())
}
fn handle_response(webview: &mut WebView<UserData>, response: &NullResult, arg: &str) {
    match response {
        Ok(_) => trace(Black.on(White), "normal response"),
        Err(e) => {
            trace(
                Black.on(White),
                &format!("could not handle execution: {}/{:?}", arg, e),
            );
        }
    }
}
fn trace(style: Style, s: &str) {
    println!("main {}", style.paint(s));
}
/** for debugging */
struct Mark {}
impl Mark {
    fn new() -> Mark {
        trace(Yellow.on(Cyan), "making mark in main");
        Self {}
    }
    fn touch(&self) {
        trace(Yellow.on(Cyan), "touching mark in main");
    }
}
impl Drop for Mark {
    fn drop(&mut self) {
        trace(Yellow.on(Cyan), "dropping mark in main");
    }
}

Cargo.toml [package] name = "webview-test" version = "0.1.0" authors = ["martin m.e@acm.org"] edition = "2018"

[dependencies]

ansi_term = "0.12.1" rust-embed = "5.1.0" web-view = "0.5.2" quick-error = "1.2.2"

richardhozak commented 4 years ago

Thank you for the reproducation example, I was able to reproduce this and can see that there are indeed some malloc issues. You can even try this with minimal example, the result is the same. I remember that there were some leaks that were fixed by @green-s in this commit 57c0669adf47e1b4d13401fdd8881eb010ec0b46 maybe he would know?

martinellison commented 4 years ago

I have run the following examples from git@github.com:Boscop/web-view.git (commit latest at writing, 7886615) under valgrind memcheck, and they all exhibit similar errors to those in my original post.

So you don't need my example above; just use the standard examples.

I have checked the following examples from git@github.com:zserge/webview.git (the original C code wrapped by the rust crate, at commit 16c93bcaea):

So it seems that the error may be in the original (c language) library. I have raised an error against the c language library: https://github.com/zserge/webview/issues/292.

I should add, that