From 20dc5bef66a6a93392b0dc4892d29934e4678cdb Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Jul 2026 17:06:45 +0100 Subject: [PATCH 1/2] Add qsort and bsearch safe rules --- rules/cstdlib/tgt_refcount.rs | 47 ++++++++ tests/unit/out/refcount/qsort_bsearch.rs | 133 +++++++++++++++++++++++ tests/unit/qsort_bsearch.c | 1 - 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 tests/unit/out/refcount/qsort_bsearch.rs diff --git a/rules/cstdlib/tgt_refcount.rs b/rules/cstdlib/tgt_refcount.rs index 060dd534..db5a3d69 100644 --- a/rules/cstdlib/tgt_refcount.rs +++ b/rules/cstdlib/tgt_refcount.rs @@ -18,3 +18,50 @@ fn f4(a0: AnyPtr, a1: usize) -> AnyPtr { fn f5(a0: usize, a1: usize) -> AnyPtr { libcc2rs::calloc_refcount(a0, a1) } + +fn f8(a0: AnyPtr, a1: AnyPtr, a2: usize, a3: usize, a4: fn(AnyPtr, AnyPtr) -> i32) -> AnyPtr { + let __base = a1.reinterpret_cast::(); + let mut __lo: isize = 0; + let mut __hi: isize = a2 as isize - 1; + let mut __found: Option = None; + while __lo <= __hi && __found.is_none() { + let __mid = (__lo + __hi) / 2; + let __elem = __base.offset(__mid as usize * a3); + let __r = a4(a0.clone(), __elem.to_any()); + if __r == 0 { + __found = Some(__elem.to_any()); + } else if __r < 0 { + __hi = __mid - 1; + } else { + __lo = __mid + 1; + } + } + match __found { + Some(__p) => __p, + None => AnyPtr::default(), + } +} + +fn f9(a0: AnyPtr, a1: usize, a2: usize, a3: fn(AnyPtr, AnyPtr) -> i32) { + let __base = a0.reinterpret_cast::(); + for __i in 0..a1 { + let mut __min = __i; + for __j in (__i + 1)..a1 { + if a3( + __base.offset(__j * a2).to_any(), + __base.offset(__min * a2).to_any(), + ) < 0 + { + __min = __j; + } + } + if __min != __i { + for __b in 0..a2 { + let __x = __base.offset(__i * a2 + __b).read(); + let __y = __base.offset(__min * a2 + __b).read(); + __base.offset(__i * a2 + __b).write(__y); + __base.offset(__min * a2 + __b).write(__x); + } + } + } +} diff --git a/tests/unit/out/refcount/qsort_bsearch.rs b/tests/unit/out/refcount/qsort_bsearch.rs new file mode 100644 index 00000000..8f820632 --- /dev/null +++ b/tests/unit/out/refcount/qsort_bsearch.rs @@ -0,0 +1,133 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn cmp_int_0(a: AnyPtr, b: AnyPtr) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + let x: Value = Rc::new(RefCell::new( + ((*a.borrow()).reinterpret_cast::().read()), + )); + let y: Value = Rc::new(RefCell::new( + ((*b.borrow()).reinterpret_cast::().read()), + )); + return ((((*x.borrow()) > (*y.borrow())) as i32) - (((*x.borrow()) < (*y.borrow())) as i32)); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let arr: Value> = Rc::new(RefCell::new(Box::new([5, 2, 9, 1, 7, 3, 8, 4]))); + { + let __base = ((arr.as_pointer() as Ptr) as Ptr) + .to_any() + .reinterpret_cast::(); + for __i in 0..8_usize { + let mut __min = __i; + for __j in (__i + 1)..8_usize { + if cmp_int_0( + __base.offset(__j * ::std::mem::size_of::()).to_any(), + __base.offset(__min * ::std::mem::size_of::()).to_any(), + ) < 0 + { + __min = __j; + } + } + if __min != __i { + for __b in 0..::std::mem::size_of::() { + let __x = __base + .offset(__i * ::std::mem::size_of::() + __b) + .read(); + let __y = __base + .offset(__min * ::std::mem::size_of::() + __b) + .read(); + __base + .offset(__i * ::std::mem::size_of::() + __b) + .write(__y); + __base + .offset(__min * ::std::mem::size_of::() + __b) + .write(__x); + } + } + } + }; + let i: Value = Rc::new(RefCell::new(0)); + 'loop_: while ((((*i.borrow()) < 7) as i32) != 0) { + assert!( + ((((*arr.borrow())[(*i.borrow()) as usize] + <= (*arr.borrow())[((*i.borrow()) + 1) as usize]) as i32) + != 0) + ); + (*i.borrow_mut()).prefix_inc(); + } + let key: Value = Rc::new(RefCell::new(7)); + let hit: Value> = Rc::new(RefCell::new( + { + let __base = ((arr.as_pointer() as Ptr) as Ptr) + .to_any() + .reinterpret_cast::(); + let mut __lo: isize = 0; + let mut __hi: isize = 8_usize as isize - 1; + let mut __found: Option = None; + while __lo <= __hi && __found.is_none() { + let __mid = (__lo + __hi) / 2; + let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); + let __r = cmp_int_0( + ((key.as_pointer()) as Ptr).to_any().clone(), + __elem.to_any(), + ); + if __r == 0 { + __found = Some(__elem.to_any()); + } else if __r < 0 { + __hi = __mid - 1; + } else { + __lo = __mid + 1; + } + } + match __found { + Some(__p) => __p, + None => AnyPtr::default(), + } + } + .reinterpret_cast::(), + )); + assert!((((!((*hit.borrow()).is_null())) as i32) != 0)); + assert!((((((*hit.borrow()).read()) == 7) as i32) != 0)); + let miss_key: Value = Rc::new(RefCell::new(42)); + let miss: Value> = Rc::new(RefCell::new( + { + let __base = ((arr.as_pointer() as Ptr) as Ptr) + .to_any() + .reinterpret_cast::(); + let mut __lo: isize = 0; + let mut __hi: isize = 8_usize as isize - 1; + let mut __found: Option = None; + while __lo <= __hi && __found.is_none() { + let __mid = (__lo + __hi) / 2; + let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); + let __r = cmp_int_0( + ((miss_key.as_pointer()) as Ptr).to_any().clone(), + __elem.to_any(), + ); + if __r == 0 { + __found = Some(__elem.to_any()); + } else if __r < 0 { + __hi = __mid - 1; + } else { + __lo = __mid + 1; + } + } + match __found { + Some(__p) => __p, + None => AnyPtr::default(), + } + } + .reinterpret_cast::(), + )); + assert!(((((*miss.borrow()).is_null()) as i32) != 0)); + return 0; +} diff --git a/tests/unit/qsort_bsearch.c b/tests/unit/qsort_bsearch.c index 4b394120..f07b8549 100644 --- a/tests/unit/qsort_bsearch.c +++ b/tests/unit/qsort_bsearch.c @@ -1,4 +1,3 @@ -// no-compile: refcount #include #include #include From 1f5a7c95d912a5c7f2b0eb523e6af7402c0799a3 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 16 Jul 2026 12:11:57 +0100 Subject: [PATCH 2/2] Avoid overflow in computation of mid point --- rules/cstdlib/tgt_refcount.rs | 13 +++++------- tests/unit/out/refcount/qsort_bsearch.rs | 26 +++++++++--------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/rules/cstdlib/tgt_refcount.rs b/rules/cstdlib/tgt_refcount.rs index db5a3d69..5c52137d 100644 --- a/rules/cstdlib/tgt_refcount.rs +++ b/rules/cstdlib/tgt_refcount.rs @@ -23,23 +23,20 @@ fn f8(a0: AnyPtr, a1: AnyPtr, a2: usize, a3: usize, a4: fn(AnyPtr, AnyPtr) -> i3 let __base = a1.reinterpret_cast::(); let mut __lo: isize = 0; let mut __hi: isize = a2 as isize - 1; - let mut __found: Option = None; - while __lo <= __hi && __found.is_none() { - let __mid = (__lo + __hi) / 2; + let mut __found = AnyPtr::default(); + while __lo <= __hi && __found.is_null() { + let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * a3); let __r = a4(a0.clone(), __elem.to_any()); if __r == 0 { - __found = Some(__elem.to_any()); + __found = __elem.to_any(); } else if __r < 0 { __hi = __mid - 1; } else { __lo = __mid + 1; } } - match __found { - Some(__p) => __p, - None => AnyPtr::default(), - } + __found } fn f9(a0: AnyPtr, a1: usize, a2: usize, a3: fn(AnyPtr, AnyPtr) -> i32) { diff --git a/tests/unit/out/refcount/qsort_bsearch.rs b/tests/unit/out/refcount/qsort_bsearch.rs index 8f820632..d53ecb1d 100644 --- a/tests/unit/out/refcount/qsort_bsearch.rs +++ b/tests/unit/out/refcount/qsort_bsearch.rs @@ -72,26 +72,23 @@ fn main_0() -> i32 { .reinterpret_cast::(); let mut __lo: isize = 0; let mut __hi: isize = 8_usize as isize - 1; - let mut __found: Option = None; - while __lo <= __hi && __found.is_none() { - let __mid = (__lo + __hi) / 2; + let mut __found = AnyPtr::default(); + while __lo <= __hi && __found.is_null() { + let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); let __r = cmp_int_0( ((key.as_pointer()) as Ptr).to_any().clone(), __elem.to_any(), ); if __r == 0 { - __found = Some(__elem.to_any()); + __found = __elem.to_any(); } else if __r < 0 { __hi = __mid - 1; } else { __lo = __mid + 1; } } - match __found { - Some(__p) => __p, - None => AnyPtr::default(), - } + __found } .reinterpret_cast::(), )); @@ -105,26 +102,23 @@ fn main_0() -> i32 { .reinterpret_cast::(); let mut __lo: isize = 0; let mut __hi: isize = 8_usize as isize - 1; - let mut __found: Option = None; - while __lo <= __hi && __found.is_none() { - let __mid = (__lo + __hi) / 2; + let mut __found = AnyPtr::default(); + while __lo <= __hi && __found.is_null() { + let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); let __r = cmp_int_0( ((miss_key.as_pointer()) as Ptr).to_any().clone(), __elem.to_any(), ); if __r == 0 { - __found = Some(__elem.to_any()); + __found = __elem.to_any(); } else if __r < 0 { __hi = __mid - 1; } else { __lo = __mid + 1; } } - match __found { - Some(__p) => __p, - None => AnyPtr::default(), - } + __found } .reinterpret_cast::(), ));