statrs-dev / statrs

Statistical computation library for Rust

Home Page:https://docs.rs/statrs/latest/statrs/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

segfault in `select_inplace` from v0.12

jonathanstrong opened this issue · comments

gdb output:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000055dd04d94b20 in statrs::statistics::slice_statistics::select_inplace ()
[Current thread is 1 (Thread 0x7f4ce53fe700 (LWP 2292366))]
(gdb) bt
#0  0x000055dd04d94b20 in statrs::statistics::slice_statistics::select_inplace ()
#1  0x000055dd04d94417 in statrs::statistics::slice_statistics::<impl statrs::statistics::order_statistics::OrderStatistics<f64> for [f64]>::quantile ()

I think my input slice to quantile had NaN values in it. from experimenting, I was able to trigger similar crashes (on v0.12 codebase) if I put a bunch of NaN values into the slice.

relevant convo about use of unsafe: #109

on a local codebase, I swapped in the safer replacement code that was made in the pull request linked above, and was able to get this panic output:

---- statistics::slice_statistics::test::check_quantile_on_256k_slice stdout ----
thread 'statistics::slice_statistics::test::check_quantile_on_256k_slice' panicked at 'index out of bounds: the len is 262144 but the index is 262144', src/statistics/slice_statistics.rs:340:20
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

which corresponds to

        // inside select_inplace
        loop {
            loop {
                begin += 1;
                if arr[begin] >= pivot {  // <- line 340 is this one
                    break;
                }
            }
            loop {
                end -= 1;
                if arr[end] <= pivot {
                    break;
                }
            }
            if end < begin {
                break;
            }
            arr.swap(begin, end);
        }

I am using v0.12 (in a bunch of places actually) because I have code that uses the old api. would you be open to a pull request to swap in the safer version of select_inplace and issue another v0.12 release?

(here is the test that triggered the above btw)

    #[test]
    fn check_quantile_on_256k_slice() {
        for _ in 0..(1024) {
            let mut xs: Vec<f64> = rand::distributions::Standard.sample_iter(&mut thread_rng()).take(1024*256).collect();
            for i in (0..xs.len()).step_by(42) {
                xs[i] = f64::NAN;
            }
            xs.quantile(0.01) ;
            xs.quantile(0.05) ;
            xs.quantile(0.1)  ;
            xs.quantile(0.2)  ;
            xs.quantile(0.25) ;
            xs.quantile(0.3)  ;
            xs.quantile(0.4)  ;
            xs.quantile(0.45) ;
            xs.quantile(0.5)  ;
            xs.quantile(0.55) ;
            xs.quantile(0.6)  ;
            xs.quantile(0.65) ;
            xs.quantile(0.7)  ;
            xs.quantile(0.75) ;
            xs.quantile(0.8)  ;
            xs.quantile(0.9)  ;
            xs.quantile(0.95) ;
            xs.quantile(0.99) ;
        }
    }