#'?' operator in Lazy::new closure?

20 messages · Page 1 of 1 (latest)

heady forge
#

I was wondering if it's possible to use the question mark operator within a Lazy::new (once_cell crate) closure or if .unwrap() is the only solution here.

grand orbit
#

i think it depends on what an error means

#

if this thing ever returns an error is that something that might be expected or a bug in your program?

heady forge
#

Something I expect I guess.

grand orbit
#

you could just have a Lazy holding a Result<T, MyErr>

#

Then you'd need to handle the result everywhere you use the lazy

heady forge
#

Hmm okay I see. that makes it rather inconvenient :D So it's probably best to stick with .unwrap() / .expect() within the lazy block as it is an error that can only happen upon initialization and not every time I use the lazy

#

thanks!

grand orbit
#

Can you expand on your use case?

#

i'm not convinced there isn't a better way

#

what about using OnceCell and initializing it in main? Or even better, just dont use globals?

heady forge
#

It's a BTreeMap of addresses found within a specified memory region:

pub static ADDRESSES: Lazy<Result<BTreeMap<&str, u64>>> = Lazy::new(|| -> Result<BTreeMap<&str, u64>> {
    let addresses = PatternScanner::new(memory::get_memory_segments())
    .with_pattern(
        Section::Name(".text".into()),
        Pattern::from_str("56 8B F1 83 7E 60 00 74 44")?,
    )
    .with_pattern(
        Section::Name(".data".into()),
        Pattern::from_str("75 1B A1 ? ? ? ? 89 45 F8")?,
    )
    .scan()?;
    
    let mut iter = addresses.iter();

    Ok(BTreeMap::from([
        ("Foo", *iter.next().unwrap()),
        ("Bar", *iter.next().unwrap()),
    ]))
});

The idea is to perform the scanning only once and fill up a BTreeMap of data/code segments mapped to their found addresses. Unfortunately I can't avoid globals because I'm within a DLL which means that after the DLL initialization routine has returned, the data on the stack would be gone. I need some global state for that.

grand orbit
#

you'll have to refresh my memory a bit, iirc you can have some sort of "main" function that is executed when you load it? This " initialization routine"?

heady forge
#

Yes exactly:

#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "system" fn DllMain(_hinst_dll: HINSTANCE, fdw_reason: DWORD, _reserved: LPVOID) -> BOOL {
    match fdw_reason {
        DLL_PROCESS_ATTACH => {
            // register panic handler
            panic::set_hook(Box::new(|info| {
                println!("{info}");
                error!("{info}");
            }));
            // returns here which means I need the global state
        }
        _ => (),
    }
    TRUE
}
grand orbit
#

what about ```rust
pub static ADDRESSES: OnceCell<???> = OnceCell::new();

#[no_mangle]
pub fn dll_main(???) -> ??? {
let addresses = ...;

match addresses{
    Ok(value) => ADDRESSES.set(value),
    Err(e) => return false
}

}```

heady forge
#

ah i see, yeah that could work. this way I can return early in case the initialization fails

#

and everytime i access ADDRESSES, I wouldn't need to unwrap anymore

grand orbit
#

right

heady forge
#

that clarifies it, thanks for your time :)