From bd838a288a385b198f5407e04b7e158692d33249 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 13 May 2026 13:29:07 +0100 Subject: [PATCH] Add rules for malloc, realloc, and free --- rules/cstdlib/ir_unsafe.json | 85 ++++++++++++++++++++ rules/cstdlib/src.cpp | 6 ++ rules/cstdlib/tgt_unsafe.rs | 12 +++ tests/unit/malloc_realloc_free.c | 32 ++++++++ tests/unit/out/unsafe/malloc_realloc_free.rs | 48 +++++++++++ 5 files changed, 183 insertions(+) create mode 100644 tests/unit/malloc_realloc_free.c create mode 100644 tests/unit/out/unsafe/malloc_realloc_free.rs diff --git a/rules/cstdlib/ir_unsafe.json b/rules/cstdlib/ir_unsafe.json index c4c71987..8a8481d2 100644 --- a/rules/cstdlib/ir_unsafe.json +++ b/rules/cstdlib/ir_unsafe.json @@ -5,5 +5,90 @@ "text": "std::process::abort();" } ] + }, + "f2": { + "body": [ + { + "text": "libc::free(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "*mut ::libc::c_void", + "is_unsafe_pointer": true + } + } + }, + "f3": { + "body": [ + { + "text": "libc::malloc(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": " as ::libc::size_t)" + } + ], + "params": { + "a0": { + "type": "u64" + } + }, + "return_type": { + "type": "*mut ::libc::c_void", + "is_unsafe_pointer": true + } + }, + "f4": { + "body": [ + { + "text": "libc::realloc(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": " as ::libc::size_t)" + } + ], + "params": { + "a0": { + "type": "*mut ::libc::c_void", + "is_unsafe_pointer": true + }, + "a1": { + "type": "u64" + } + }, + "return_type": { + "type": "*mut ::libc::c_void", + "is_unsafe_pointer": true + } } } diff --git a/rules/cstdlib/src.cpp b/rules/cstdlib/src.cpp index f6a75f59..b93859c9 100644 --- a/rules/cstdlib/src.cpp +++ b/rules/cstdlib/src.cpp @@ -4,3 +4,9 @@ #include void f1() { return std::abort(); } + +void f2(void *a0) { return free(a0); } + +void *f3(size_t a0) { return malloc(a0); } + +void *f4(void *a0, size_t a1) { return realloc(a0, a1); } diff --git a/rules/cstdlib/tgt_unsafe.rs b/rules/cstdlib/tgt_unsafe.rs index f053d260..2f7491e5 100644 --- a/rules/cstdlib/tgt_unsafe.rs +++ b/rules/cstdlib/tgt_unsafe.rs @@ -4,3 +4,15 @@ unsafe fn f1() { std::process::abort(); } + +unsafe fn f2(a0: *mut ::libc::c_void) { + libc::free(a0) +} + +unsafe fn f3(a0: u64) -> *mut ::libc::c_void { + libc::malloc(a0 as ::libc::size_t) +} + +unsafe fn f4(a0: *mut ::libc::c_void, a1: u64) -> *mut ::libc::c_void { + libc::realloc(a0, a1 as ::libc::size_t) +} diff --git a/tests/unit/malloc_realloc_free.c b/tests/unit/malloc_realloc_free.c new file mode 100644 index 00000000..709855d3 --- /dev/null +++ b/tests/unit/malloc_realloc_free.c @@ -0,0 +1,32 @@ +// no-compile: refcount +#include +#include + +int main() { + int *p = (int *)malloc(sizeof(int)); + *p = 42; + assert(*p == 42); + free(p); + + int *arr = (int *)malloc(4 * sizeof(int)); + for (int i = 0; i < 4; i++) { + arr[i] = i * 10; + } + assert(arr[0] == 0); + assert(arr[3] == 30); + free(arr); + + int *grow = (int *)malloc(2 * sizeof(int)); + grow[0] = 1; + grow[1] = 2; + grow = (int *)realloc(grow, 4 * sizeof(int)); + grow[2] = 3; + grow[3] = 4; + assert(grow[0] == 1); + assert(grow[1] == 2); + assert(grow[2] == 3); + assert(grow[3] == 4); + free(grow); + + return 0; +} diff --git a/tests/unit/out/unsafe/malloc_realloc_free.rs b/tests/unit/out/unsafe/malloc_realloc_free.rs new file mode 100644 index 00000000..9bade33b --- /dev/null +++ b/tests/unit/out/unsafe/malloc_realloc_free.rs @@ -0,0 +1,48 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut p: *mut i32 = + (libc::malloc(::std::mem::size_of::() as u64 as ::libc::size_t) as *mut i32); + (*p) = 42; + assert!(((((*p) == (42)) as i32) != 0)); + libc::free((p as *mut i32 as *mut ::libc::c_void)); + let mut arr: *mut i32 = (libc::malloc( + (4_u64).wrapping_mul(::std::mem::size_of::() as u64 as u64) as ::libc::size_t, + ) as *mut i32); + let mut i: i32 = 0; + 'loop_: while ((((i) < (4)) as i32) != 0) { + (*arr.offset((i) as isize)) = ((i) * (10)); + i.postfix_inc(); + } + assert!(((((*arr.offset((0) as isize)) == (0)) as i32) != 0)); + assert!(((((*arr.offset((3) as isize)) == (30)) as i32) != 0)); + libc::free((arr as *mut i32 as *mut ::libc::c_void)); + let mut grow: *mut i32 = (libc::malloc( + (2_u64).wrapping_mul(::std::mem::size_of::() as u64 as u64) as ::libc::size_t, + ) as *mut i32); + (*grow.offset((0) as isize)) = 1; + (*grow.offset((1) as isize)) = 2; + grow = (libc::realloc( + (grow as *mut i32 as *mut ::libc::c_void), + (4_u64).wrapping_mul(::std::mem::size_of::() as u64 as u64) as ::libc::size_t, + ) as *mut i32); + (*grow.offset((2) as isize)) = 3; + (*grow.offset((3) as isize)) = 4; + assert!(((((*grow.offset((0) as isize)) == (1)) as i32) != 0)); + assert!(((((*grow.offset((1) as isize)) == (2)) as i32) != 0)); + assert!(((((*grow.offset((2) as isize)) == (3)) as i32) != 0)); + assert!(((((*grow.offset((3) as isize)) == (4)) as i32) != 0)); + libc::free((grow as *mut i32 as *mut ::libc::c_void)); + return 0; +}