dioxus icon indicating copy to clipboard operation
dioxus copied to clipboard

Trying `subsecond` and: `Ignoring hotpatch since there is no ASLR reference`. What does it mean?

Open frederikhors opened this issue 9 months ago • 20 comments

I'm trying for the first time https://docs.rs/subsecond/0.7.0-alpha.0/subsecond/index.html.

I have a small-size project (86642 lines of Rust code).

I changed this function:

impl Player {
    pub fn to_css(&self, css_source: &str) -> Result<String> {
        let result = css_source
            .replace("{{number}}", &self.number.to_string())
            .replace("{{height}}", &calculate_height(&self));

        Ok(result)
    }
}

to this:

impl Player {
    pub fn to_css(&self, css_source: &str) -> Result<String> {
        subsecond::call(|| {
            let result = css_source
                .replace("{{number}}", &self.number.to_string())
                .replace("{{height}}", &calculate_height(&self));

            Ok(result)
        })
    }
}

and launched this:

cargo binstall [email protected]

and then:

dx serve --package app --hotpatch

after a few moments it starts and axum is listening on its 8080 port. Good!

Then I change one line in the to_css function and boom:

[dev] Ignoring hotpatch since there is no ASLR reference. Is the client connected?

What does it mean?

frederikhors avatar May 25 '25 08:05 frederikhors

Hey! We should probably change the logging here. This is because your client has not connected to the dioxus devtools server (we don't do this implicitly).

Add a

dioxus::dioxus_devtools::connect_subsecond();

to your main to connect to our devtools socket, and then things should start working.

Also, currently, capturing closures are not working properly with subsecond (they worked at some point) - will need to use the closure as a function:

impl Player {
    pub fn to_css(&self, css_source: &str) -> Result<String> {
        subsecond::current(|css_source| { /* ... */ }).call(css_source)
    }
}

See this bevy demo as an example:

https://github.com/jkelleyrtp/subsecond-bevy-demo/blob/b33b702dd30067d262c7d6b9ec89f489b3bf26e6/src/main.rs#L7

jkelleyrtp avatar May 25 '25 12:05 jkelleyrtp

Ok I tried. Unfortunately bad news.

  1. dioxus::dioxus_devtools::connect_subsecond() doesn't, dioxus_devtools::connect_subsecond() works;

  2. subsecond::current:

    error[E0425]: cannot find function `current` in crate `subsecond`
    |
    13 |         subsecond::current(|css_source| {
    |                    ^^^^^^^ not found in `subsecond`
    |
    help: consider importing this function
    |
    1  + use std::thread::current;
    |
    help: if you import `current`, refer to it directly
    |
    13 -         subsecond::current(|css_source| {
    13 +         current(|css_source| {
    |
    
  3. If I use subsecond::call(|| {...}) I get in the console:

    Hot-patching: C:\project\css.rs took 2735ms
    

    so 2.7 seconds instead of 13 seconds with Cargo (night and day for me) BUT it seems like it's working and instead IT'S NOT WORKING! Poor me!

    The function to_css gets called but it doesn't return the new (edited result). The string returned is always the one before the edit.

frederikhors avatar May 26 '25 00:05 frederikhors

Subsecond::HotFn::current() - my bad!

Use the bevy template as a light guide.

jkelleyrtp avatar May 26 '25 00:05 jkelleyrtp

Ok, thanks.

  1. subsecond::HotFn::current(|css_source: &str| {}}).call((css_source)) works but unfortunately the same as before: the function to_css gets called but it doesn't return the new (edited result). The string returned is always the one before the edit.

I also tried removing subsecond completely, using only dx serve --package app --hotpatch and the result is the same:

Hot-patching: C:\project\css.rs took 2881ms

but the result doesn't change after the edit and save.

What can be the cause?

It's a simple function that replaces parts of a string.

frederikhors avatar May 26 '25 00:05 frederikhors

@frederikhors You might have to depend on the latest git version of subsecond. For me, the current alpha of subsecond did not work.

A day ago, I successfully used these versions.

dioxus-devtools = { version = "0.7.0-alpha.0", git = "https://github.com/DioxusLabs/dioxus.git", rev = "b2bd1f" }

and

cargo install dioxus-cli --git https://github.com/DioxusLabs/dioxus --rev b2bd1f

Copied from TheBevyFlock/bevy_simple_subsecond_system.

stefnotch avatar May 26 '25 06:05 stefnotch

Ok, thanks.

Ok I added the git version at commit b2bd1f.

I start dx and after one edit to one file (no subsecond code involved) I get this:

[dev] Build failed: Runtime Error: Build panicked! JoinError::Panic(Id(270), "failed to resolve patch symbols: RuntimeError(Failed to find ___aslr_reference symbol\n\nStack backtrace:\n   0: git_index_checksum\n   1: git_index_checksum\n   2: git_filter_source_repo\n   3: git_filter_source_repo\n   4: git_filter_source_repo\n   5: git_filter_source_repo\n   6: git_filter_source_repo\n   7: git_index_checksum\n   8: git_index_checksum\n   9: git_index_checksum\n  10: git_index_checksum\n  11: git_index_checksum\n  12: git_index_checksum\n  13: git_index_checksum\n  14: git_index_checksum\n  15: git_index_checksum\n  16: git_index_checksum\n  17: git_index_checksum\n  18: BaseThreadInitThunk\n  19: RtlUserThreadStart)", ...)

What is it?

frederikhors avatar May 26 '25 21:05 frederikhors

I fixed the issues with Runtime Error: Build panicked! JoinError::Panic(Id(270) by re-installing cargo install dioxus-cli --git https://github.com/DioxusLabs/dioxus --rev b2bd1f.

But now I'm trying it and it doesn't work. The string of the function called from axum API is the same, no matter what changes I made to the .rs file.

I'll create a reproduction ASAP.

frederikhors avatar May 26 '25 22:05 frederikhors

Ok I created a reproduction:

Cargo.toml:

[package]
name = "app"
version = "0.1.0"
edition = "2024"

[dependencies]
axum = "0.8.4"
dioxus-devtools = { version = "=0.7.0-alpha.0", git = "https://github.com/DioxusLabs/dioxus.git", rev = "b2bd1f" }
tokio = { version = "1.0", features = ["full"] }

[profile]

[profile.wasm-dev]
inherits = "dev"
opt-level = 1

[profile.server-dev]
inherits = "dev"

[profile.android-dev]
inherits = "dev"

main.rs:

use axum::{Router, routing::get};

#[tokio::main]
async fn main() {
    dioxus_devtools::connect_subsecond();

    let app = Router::new().route("/", get(handler));

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();

    println!("listening on {}", listener.local_addr().unwrap());

    axum::serve(listener, app).await.unwrap();
}

async fn handler() -> String {
    let mut res = "Hello, World!".to_string();

    res = res.replace("World", "Moon");

    res
}

Steps:

  1. start dx with: dx serve --hotpatch

  2. open the browser to http://localhost:3000

  3. edit "Moon" with something else

  4. reload the browser page

  5. the text is the same, Moon is still there

frederikhors avatar May 26 '25 22:05 frederikhors

@frederikhors Wait, I don't see the dioxus_devtools::subsecond::HotFn::current call in the reproduction?

stefnotch avatar May 27 '25 06:05 stefnotch

@frederikhors Wait, I don't see the dioxus_devtools::subsecond::HotFn::current call in the reproduction?

Doesn't work with or without it.

frederikhors avatar May 27 '25 08:05 frederikhors

Ah, subsecond has a bug with async!

Apparently trying to do dioxus_devtools::subsecond::HotFn::current(handler) where handler is an async fn does not work for me (Windows 11).

Meanwhile rewriting it to be a fn -> impl Future does work.

use axum::{Router, routing::get};

#[tokio::main]
async fn main() {
    dioxus_devtools::connect_subsecond();

    let app = Router::new().route("/", get(handler_wrapper));

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();

    println!("listening on {}", listener.local_addr().unwrap());

    axum::serve(listener, app).await.unwrap();
}

async fn handler_wrapper() -> String {
    dioxus_devtools::subsecond::HotFn::current(handler)
        .call(())
        .await
}


// Does NOT get hot patched
/*
async fn handler() -> String {
    let mut res = "Booom, World!".to_string();

    res = res.replace("World", "Moon");

    res
}
*/

// Does get hot patched
fn handler() -> impl Future<Output = String> {
    let mut res = "Booom, World!".to_string();

    res = res.replace("World", "Moon");

    async { res }
}

stefnotch avatar May 27 '25 08:05 stefnotch

@jkelleyrtp Should I open a new issue to track that async bug?

stefnotch avatar May 27 '25 08:05 stefnotch

I am getting a different error for axum, after I changed the code it shows the error

22:38:20 [dev] Build failed: Runtime Error: Build panicked! JoinError::Panic(Id(31), "failed to resolve patch symbols: RuntimeError(Failed to find ___aslr_reference symbol\n\nStack backtrace:\n   0: dx::build::patch::create_undefined_symbol_stub\n   1: dx::build::request::BuildRequest::build::{{closure}}\n   2: dx::build::builder::AppBuilder::patch_rebuild::{{closure}}\n   3: tokio::runtime::task::core::Core<T,S>::poll\n   4: tokio::runtime::task::harness::Harness<T,S>::poll\n   5: tokio::runtime::scheduler::multi_thread::worker::Context::run_task\n   6: tokio::runtime::context::scoped::Scoped<T>::set\n   7: tokio::runtime::context::runtime::enter_runtime\n   8: tokio::runtime::scheduler::multi_thread::worker::run\n   9: <tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll\n  10: tokio::runtime::task::core::Core<T,S>::poll\n  11: tokio::runtime::task::harness::Harness<T,S>::poll\n  12: tokio::runtime::blocking::pool::Inner::run\n  13: std::sys::backtrace::__rust_begin_short_backtrace\n  14: core::ops::function::FnOnce::call_once{{vtable.shim}}\n  15: std::sys::pal::unix::thread::Thread::new::thread_start\n  16: <unknown>\n  17: <unknown>)", ...)
Cargo.toml
[package]
name = "axum-hello"
version = "0.1.0"
edition = "2024"

[dependencies]
axum = "0.8.4"
tokio = { version = "1.45.1", features = ["full"] }
dioxus-devtools = { version = "0.7.0-alpha.0", git = "https://github.com/DioxusLabs/dioxus.git" }
src/main.rs
use axum::{response::Html, routing::get, Router};

#[tokio::main]
async fn main() {
    dioxus_devtools::connect_subsecond();
    let app = Router::new().route("/", get(handler));
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    println!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

async fn handler() -> Html<&'static str> {
    dioxus_devtools::subsecond::call(|| {
        Html("<h1>Hello, World!</h1>")
    })
}

One surprising thing I noticed after bevy compiles is that the file was modified, I have to reload my editor (helix) manually with :reload.

pickfire avatar May 27 '25 14:05 pickfire

You might have a different version of Dioxus and the CLI. In the most recent commit we moved from __aslr_reference to just using 'main'

jkelleyrtp avatar May 27 '25 15:05 jkelleyrtp

Ah nice, seemed to work now.

pickfire avatar May 27 '25 16:05 pickfire

Image

Can subsecond have serde being ^1 so that it can be more portable for packages that uses an older serde version? I wanted to add a hello world example to axum but it didn't work due to that error.

pickfire avatar May 27 '25 17:05 pickfire

With the devtools at main branch the axum small example works. My real case still doesn't work. The string is not replaced. I cannot understand why. And I cannot create a reproduction because it's complex. Lot of async calls.

frederikhors avatar May 27 '25 20:05 frederikhors

@frederikhors Have you been able to get it to work under some very specific circumstances in your real case? That might help the Dioxus team narrow it down.

One of the first things I tried in the reproduction case was "avoiding async". That seemed to work reliably. And then I tried out more cases.

async fn handler() -> String {
    dioxus_devtools::subsecond::HotFn::current(sync_handler)
        .call(())
        .await
}
fn sync_handler() -> String {
    let mut res = "Booom, World!".to_string();

    res = res.replace("World", "Moon");

    res
}

Another thing: If your real project has multiple crates, then it's very possible that it just outright won't work due to #4160

stefnotch avatar May 27 '25 21:05 stefnotch

Yeah @stefnotch i have many crates. It may be.

frederikhors avatar May 27 '25 21:05 frederikhors

dioxus_devtools::connect_subsecond(); was exactly what I needed.

I've been trying to get a working binary hotpatching example working on Windows, and up until now this was my latest stumbling block.

I do have other issues regarding the linker I'm now trying to sort out, first upon initial build and now with the invoked linker on code change, but this helped me advance a step.

devnought avatar Jun 09 '25 07:06 devnought

The async issue was re-reported here https://github.com/DioxusLabs/dioxus/issues/4305

stefnotch avatar Jul 07 '25 21:07 stefnotch

I think since the issue here was related to problems with setup, and subsecond now has a serve method as well as dioxus::serve, we can close this.

jkelleyrtp avatar Oct 28 '25 19:10 jkelleyrtp