nkaz001 / hftbacktest

A high-frequency trading and market-making backtesting tool in Python and Rust, which accounts for limit orders, queue positions, and latencies, utilizing full tick data for trades and order books, with real-world crypto market-making examples for Binance Futures
MIT License
1.78k stars 357 forks source link

Memory corruption (STATUS_HEAP_CORRUPTION) when using Vec::from_raw_parts in aligned_vec function #101

Closed dogfood1 closed 1 month ago

dogfood1 commented 1 month ago

I'm encountering a heap corruption error when using a custom aligned_vec function that attempts to create an aligned buffer. The error occurs specifically at the Vec::from_raw_parts call.

Code

The problematic function is as follows:


fn aligned_vec(size: usize) -> Box<[u8]> {
    let capacity = (size / size_of::<Align64>()) + 1;
    let mut aligned: Vec<Align64> = Vec::with_capacity(capacity);

    let ptr = aligned.as_mut_ptr();
    let cap = aligned.capacity();

    forget(aligned);

    unsafe {
       Exception 0x80000003 encountered at address 0x7ffc0809c882---------> Vec::from_raw_parts(ptr as *mut u8, size, cap * size_of::<Align64>()).into_boxed_slice()
    }
}

error: process didn't exit successfully: `target\debug\examples\gridtrading_backtest.exe` (exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)

Any ideas on how to solve this?
dogfood1 commented 1 month ago

I tried it on Linux and did not encounter the same issue. This problem seems to only affect Windows. I don't think Windows support is important, so this issue can probably be closed.

nkaz001 commented 1 month ago

Thank you for reporting this. I didn't test it on Windows, but I will look into it when I have a chance.

nkaz001 commented 1 month ago

This fix might resolve the issue on Windows. Please check when you have a moment.

dogfood1 commented 1 month ago

I still encountered errors after trying to pull the patch and i fixed another function, aligned_vec_i64, according to the patch method, but there are still issues. The new problem is as follows:

   #[inline]
    fn elapse(&mut self, duration: i64) -> Result<bool, Self::Error> {
        if self.cur_ts == i64::MAX {
            self.initialize_evs()?;
            match self.evs.next() {
                Some(ev) => {
                    self.cur_ts = ev.timestamp;
                }
                None => {
                    return Ok(false);
                }
            }
        }
      Exception 0xc0000409 encountered at address 0x7ff74bd6ece2  ->>>>>>>>>>>self.goto::<false>(self.cur_ts + duration, WaitOrderResponse::None)
    }

The stack is as follows

std::panicking::rust_panic_with_hook() panicking.rs:814
std::panicking::begin_panic_handler::closure$0() panicking.rs:656
std::sys_common::backtrace::__rust_end_short_backtrace<std::panicking::begin_panic_handler::closure_env$0,never$>() backtrace.rs:171
std::panicking::begin_panic_handler() panicking.rs:652
core::panicking::panic_nounwind_fmt::runtime() panicking.rs:110
core::panicking::panic_nounwind_fmt() panicking.rs:120
core::panicking::panic_nounwind() panicking.rs:219
core::slice::index::impl$2::get_unchecked_mut::precondition_check(u64,u64) ub_checks.rs:68
core::slice::index::impl$2::get_unchecked_mut<alloc::boxed::Box<dyn$<hftbacktest::backtest::proc::proc::LocalProcessor<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,hftbacktest::types::Event> >,alloc::alloc::Global> >(u64,ptr_mut$<slice2$<alloc::boxed::Box<dyn$<hftbacktest::backtest::proc::proc::LocalProcessor<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,hftbacktest::types::Event> >,alloc::alloc::Global> > >) ub_checks.rs:75
core::slice::impl$0::get_unchecked_mut<alloc::boxed::Box<dyn$<hftbacktest::backtest::proc::proc::LocalProcessor<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,hftbacktest::types::Event> >,alloc::alloc::Global>,usize>(ref_mut$<slice2$<alloc::boxed::Box<dyn$<hftbacktest::backtest::proc::proc::LocalProcessor<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,hftbacktest::types::Event> >,alloc::alloc::Global> > >,u64) mod.rs:728
hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>::goto<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,false>(i64,enum2$<hftbacktest::types::WaitOrderResponse>) backtest.rs:172
hftbacktest::backtest::backtest::impl$2::elapse<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>(*mut hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>,i64) backtest.rs:454
gridtrading_backtest::algo::gridtrading<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>,hftbacktest::backtest::recorder::BacktestRecorder>(*mut hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>,*mut hftbacktest::backtest::recorder::BacktestRecorder,f64,f64,u64,f64,f64,f64,f64) algo.rs:28
gridtrading_backtest::main() gridtrading_backtest.rs:79
core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >(*mut ) function.rs:250
core::hint::black_box(tuple$<>) hint.rs:338
std::rt::lang_start::closure$0<tuple$<> >(*mut std::rt::lang_start::closure_env$0<tuple$<> >) rt.rs:159
std::rt::lang_start_internal() rt.rs:141
std::rt::lang_start<tuple$<> >(*mut ,i64,*mut *mut u8,u8) rt.rs:158
main 0x00007ff74bbd2a29
invoke_main() 0x00007ff74bdfc930
__scrt_common_main_seh() 0x00007ff74bdfc90e
<unknown> 0x00007ffc067b257d
<unknown> 0x00007ffc07feaf28
nkaz001 commented 1 month ago

Thank you for the quick check. The new patch might resolve the issue.

dogfood1 commented 1 month ago
    Idx: SliceIndex<[u8]>,
{
    #[inline]
    fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
        let arr = unsafe { &mut *self.ptr };
        &mut arr[index]
    }
}

impl Drop for DataPtr {
    fn drop(&mut self) {
        if self.managed {
            Exception 0x80000003 encountered at address 0x7ffc0809c882 ->>>>>>>let _ = unsafe { Box::from_raw(self.ptr) };
        }
    }
}

Thank you for the quick fix. However, there is still a new issue. After running the program for a while, the above problem occurs. Here is the stack trace:

<unknown> 0x00007ffc0809c883
<unknown> 0x00007ffc080a595a
<unknown> 0x00007ffc080a5c3a
<unknown> 0x00007ffc080b1c35
<unknown> 0x00007ffc07fcc3ac
<unknown> 0x00007ffc07fcaff1
alloc::alloc::impl$1::deallocate(*mut alloc::alloc::Global,core::ptr::non_null::NonNull<u8>,core::alloc::layout::Layout) alloc.rs:256
alloc::boxed::impl$8::drop<slice2$<u8>,alloc::alloc::Global>(*mut alloc::boxed::Box<slice2$<u8>,alloc::alloc::Global>) boxed.rs:1288
core::ptr::drop_in_place<alloc::boxed::Box<slice2$<u8>,alloc::alloc::Global> >(*mut alloc::boxed::Box<slice2$<u8>,alloc::alloc::Global>) mod.rs:542
hftbacktest::backtest::reader::data::impl$6::drop(*mut hftbacktest::backtest::reader::data::DataPtr) data.rs:158
core::ptr::drop_in_place<hftbacktest::backtest::reader::data::DataPtr>(*mut hftbacktest::backtest::reader::data::DataPtr) mod.rs:542
alloc::rc::impl$28::drop<hftbacktest::backtest::reader::data::DataPtr,alloc::alloc::Global>(*mut alloc::rc::Rc<hftbacktest::backtest::reader::data::DataPtr,alloc::alloc::Global>) rc.rs:2193
core::ptr::drop_in_place<alloc::rc::Rc<hftbacktest::backtest::reader::data::DataPtr,alloc::alloc::Global> >(*mut alloc::rc::Rc<hftbacktest::backtest::reader::data::DataPtr,alloc::alloc::Global>) mod.rs:542
core::ptr::drop_in_place<hftbacktest::backtest::reader::data::Data<hftbacktest::types::Event> >(*mut hftbacktest::backtest::reader::data::Data<hftbacktest::types::Event>) mod.rs:542
hftbacktest::backtest::reader::reader::Cache<hftbacktest::types::Event>::remove<hftbacktest::types::Event>(hftbacktest::backtest::reader::data::Data<hftbacktest::types::Event>) reader.rs:67
hftbacktest::backtest::reader::reader::Reader<hftbacktest::types::Event>::release<hftbacktest::types::Event>(hftbacktest::backtest::reader::data::Data<hftbacktest::types::Event>) reader.rs:124
hftbacktest::backtest::proc::local::impl$2::process_data<hftbacktest::backtest::assettype::LinearAsset,hftbacktest::backtest::models::latency::IntpOrderLatency,hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>(*mut hftbacktest::backtest::proc::local::Local<hftbacktest::backtest::assettype::LinearAsset,hftbacktest::backtest::models::latency::IntpOrderLatency,hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>) local.rs:298
hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>::goto<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,false>(i64,enum2$<hftbacktest::types::WaitOrderResponse>) backtest.rs:156
hftbacktest::backtest::backtest::impl$2::elapse<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>(*mut hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>,i64) backtest.rs:457
gridtrading_backtest::algo::gridtrading<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth,hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>,hftbacktest::backtest::recorder::BacktestRecorder>(*mut hftbacktest::backtest::backtest::Backtest<hftbacktest::depth::hashmapmarketdepth::HashMapMarketDepth>,*mut hftbacktest::backtest::recorder::BacktestRecorder,f64,f64,u64,f64,f64,f64,f64) algo.rs:28
gridtrading_backtest::main() gridtrading_backtest.rs:79
core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >(*mut ) function.rs:250
core::hint::black_box(tuple$<>) hint.rs:338
std::rt::lang_start::closure$0<tuple$<> >(*mut std::rt::lang_start::closure_env$0<tuple$<> >) rt.rs:159
std::rt::lang_start_internal() rt.rs:141
std::rt::lang_start<tuple$<> >(*mut ,i64,*mut *mut u8,u8) rt.rs:158
main 0x00007ff6f4375579
 invoke_main() 0x00007ff6f45ab600
__scrt_common_main_seh() 0x00007ff6f45ab5de
<unknown> 0x00007ffc067b257d
<unknown> 0x00007ffc07feaf28
nkaz001 commented 1 month ago

That was my mistake; I missed fixing that part. Since I only have a Linux machine, I haven't tested it on other platforms. Thank you for your help. The new fix resolves the issue.

dogfood1 commented 1 month ago

I have tested the issue on Windows, and it has been resolved. Thank you for the prompt and efficient fix.