Skip to content

Commit 0540ecd

Browse files
Refactor null checks
1 parent d1e9f43 commit 0540ecd

File tree

1 file changed

+109
-23
lines changed

1 file changed

+109
-23
lines changed

cminesweeper/src/lib.rs

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,15 @@ pub enum CError {
2020
type GameSizeType = minesweeper::SizeType;
2121
type ArraySizeType = u64;
2222

23-
macro_rules! return_error {
23+
fn panic_if_null(c_ei_ptr: *const CErrorInfo) {
24+
if c_ei_ptr.is_null() {
25+
panic!("Error info ptr is null!")
26+
}
27+
}
28+
29+
macro_rules! populate_error {
2430
($error_info_ptr:ident, $error_code:expr, $error_msg:expr) => {{
31+
panic_if_null($error_info_ptr);
2532
let error_info = unsafe { &mut *$error_info_ptr };
2633
if $error_msg.len() > 0 && error_info.error_message_max_length > 0 {
2734
let ref error_message = $error_msg;
@@ -44,6 +51,12 @@ macro_rules! return_error {
4451
}
4552
}
4653
error_info.error_code = $error_code;
54+
}};
55+
}
56+
57+
macro_rules! return_error {
58+
($error_info_ptr:ident, $error_code:expr, $error_msg:expr) => {{
59+
populate_error!($error_info_ptr, $error_code, $error_msg);
4760
return;
4861
}};
4962
($error_info_ptr:ident, $error_code:expr) => {
@@ -70,12 +83,33 @@ macro_rules! return_or_assign {
7083

7184
macro_rules! initialize_to_ok {
7285
($error_info_ptr:ident) => {
86+
panic_if_null($error_info_ptr);
7387
let mut error_info = unsafe { &mut *$error_info_ptr };
7488
error_info.error_code = CError::Ok;
7589
error_info.error_message_length = 0;
7690
};
7791
}
7892

93+
macro_rules! get_mut_ref_from_ptr {
94+
($ptr:ident, $error_info_ptr:ident) => {
95+
if $ptr.is_null() {
96+
return_error!($error_info_ptr, CError::NullPointerAsInput);
97+
} else {
98+
unsafe { &mut *$ptr }
99+
}
100+
};
101+
}
102+
103+
macro_rules! get_ref_from_ptr {
104+
($ptr:ident, $error_info_ptr:ident) => {
105+
if $ptr.is_null() {
106+
return_error!($error_info_ptr, CError::NullPointerAsInput);
107+
} else {
108+
unsafe { &*$ptr }
109+
}
110+
};
111+
}
112+
79113
// Based on this https://s3.amazonaws.com/temp.michaelfbryan.com/objects/index.html
80114
#[repr(C)]
81115
pub struct COpenedField {
@@ -110,7 +144,7 @@ pub extern "C" fn minesweeper_new_game(
110144
if game_ptr_ptr.is_null() {
111145
return_error!(c_ei_ptr, CError::NullPointerAsInput);
112146
}
113-
let game_ptr = unsafe { &mut *game_ptr_ptr };
147+
let game_ptr = get_mut_ref_from_ptr!(game_ptr_ptr, c_ei_ptr);
114148
if !game_ptr.is_null() {
115149
return_error!(c_ei_ptr, CError::InvalidInput);
116150
}
@@ -127,11 +161,9 @@ pub extern "C" fn minesweeper_game_open(
127161
c_ei_ptr: *mut CErrorInfo,
128162
) {
129163
initialize_to_ok!(c_ei_ptr);
130-
if game_ptr.is_null() || c_open_info_ptr.is_null() {
131-
return_error!(c_ei_ptr, CError::NullPointerAsInput);
132-
}
164+
let game = get_mut_ref_from_ptr!(game_ptr, c_ei_ptr);
165+
let c_open_info = get_mut_ref_from_ptr!(c_open_info_ptr, c_ei_ptr);
133166

134-
let mut c_open_info = unsafe { &mut *c_open_info_ptr };
135167
if c_open_info.newly_opened_fields_length != 0 {
136168
return_error!(c_ei_ptr, CError::InvalidInput);
137169
}
@@ -142,7 +174,6 @@ pub extern "C" fn minesweeper_game_open(
142174
return_error!(c_ei_ptr, CError::NullPointerAsInput);
143175
}
144176

145-
let game = unsafe { &mut *game_ptr };
146177
let open_info = return_or_assign!(game.open(row, column), c_ei_ptr);
147178

148179
if open_info.newly_opened_fields.len() as ArraySizeType
@@ -176,11 +207,8 @@ pub extern "C" fn minesweeper_game_toggle_flag(
176207
c_ei_ptr: *mut CErrorInfo,
177208
) {
178209
initialize_to_ok!(c_ei_ptr);
179-
if game_ptr.is_null() || field_flag_result_ptr.is_null() {
180-
return_error!(c_ei_ptr, CError::NullPointerAsInput);
181-
}
182-
let game = unsafe { &mut *game_ptr };
183-
let flag_result = unsafe { &mut *field_flag_result_ptr };
210+
let game = get_mut_ref_from_ptr!(game_ptr, c_ei_ptr);
211+
let flag_result = get_mut_ref_from_ptr!(field_flag_result_ptr, c_ei_ptr);
184212
*flag_result = return_or_assign!(game.toggle_flag(row, column), c_ei_ptr);
185213
}
186214

@@ -190,10 +218,7 @@ pub extern "C" fn minesweeper_destroy_game(
190218
c_ei_ptr: *mut CErrorInfo,
191219
) {
192220
initialize_to_ok!(c_ei_ptr);
193-
if game_ptr_ptr.is_null() {
194-
return_error!(c_ei_ptr, CError::NullPointerAsInput);
195-
}
196-
let game_ptr = unsafe { &mut *game_ptr_ptr };
221+
let game_ptr = get_mut_ref_from_ptr!(game_ptr_ptr, c_ei_ptr);
197222
if game_ptr.is_null() {
198223
return;
199224
}
@@ -213,8 +238,8 @@ pub extern "C" fn minesweeper_game_get_width(
213238
if game_ptr.is_null() || width_ptr.is_null() {
214239
return_error!(c_ei_ptr, CError::NullPointerAsInput);
215240
}
216-
let game = unsafe { &*game_ptr };
217-
let width = unsafe { &mut *width_ptr };
241+
let game = get_ref_from_ptr!(game_ptr, c_ei_ptr);
242+
let width = get_mut_ref_from_ptr!(width_ptr, c_ei_ptr);
218243
*width = game.width();
219244
}
220245

@@ -228,8 +253,8 @@ pub extern "C" fn minesweeper_game_get_height(
228253
if game_ptr.is_null() || height_ptr.is_null() {
229254
return_error!(c_ei_ptr, CError::NullPointerAsInput);
230255
}
231-
let game = unsafe { &*game_ptr };
232-
let height = unsafe { &mut *height_ptr };
256+
let game = get_ref_from_ptr!(game_ptr, c_ei_ptr);
257+
let height = get_mut_ref_from_ptr!(height_ptr, c_ei_ptr);
233258
*height = game.height();
234259
}
235260

@@ -243,8 +268,8 @@ pub extern "C" fn minesweeper_game_get_elapsed_seconds(
243268
if game_ptr.is_null() || elapsed_seconds_ptr.is_null() {
244269
return_error!(c_ei_ptr, CError::NullPointerAsInput);
245270
}
246-
let game = unsafe { &*game_ptr };
247-
let elapsed_seconds = unsafe { &mut *elapsed_seconds_ptr };
271+
let game = get_ref_from_ptr!(game_ptr, c_ei_ptr);
272+
let elapsed_seconds = get_mut_ref_from_ptr!(elapsed_seconds_ptr, c_ei_ptr);
248273
let elapsed_duration = game.get_elapsed();
249274
*elapsed_seconds = elapsed_duration.as_secs();
250275
}
@@ -400,7 +425,15 @@ mod test {
400425
}
401426

402427
#[test]
403-
fn destroy_game_with_nullptr() {
428+
#[should_panic(expected = "Error info ptr is null!")]
429+
fn new_game_with_nullptr_as_error_info_ptr() {
430+
let level = GameLevel::Beginner;
431+
let mut game_ptr: *mut Game = std::ptr::null_mut();
432+
minesweeper_new_game(&mut game_ptr, level, std::ptr::null_mut());
433+
}
434+
435+
#[test]
436+
fn destroy_game_with_nullptr_as_game() {
404437
let mut error_info = create_empty_error_info();
405438
minesweeper_destroy_game(std::ptr::null_mut(), &mut error_info);
406439
assert_eq!(CError::NullPointerAsInput, error_info.error_code);
@@ -415,6 +448,13 @@ mod test {
415448
check_no_error(&error_info);
416449
}
417450

451+
#[test]
452+
#[should_panic(expected = "Error info ptr is null!")]
453+
fn destroy_game_with_nullptr_as_error_info_ptr() {
454+
let mut game_ptr = create_game(GameLevel::Beginner);
455+
minesweeper_destroy_game(&mut game_ptr, std::ptr::null_mut());
456+
}
457+
418458
#[test]
419459
fn create_and_destroy() {
420460
let mut error_info = create_empty_error_info();
@@ -499,6 +539,20 @@ mod test {
499539
destroy_game(&mut game_ptr);
500540
}
501541

542+
#[test]
543+
#[should_panic(expected = "Error info ptr is null!")]
544+
fn open_with_nullptr_as_error_info_ptr() {
545+
let game_ptr = create_game(GameLevel::Beginner);
546+
let mut buffered_open_info = create_open_info_with_size(5);
547+
minesweeper_game_open(
548+
game_ptr,
549+
0,
550+
0,
551+
&mut buffered_open_info.data,
552+
std::ptr::null_mut(),
553+
);
554+
}
555+
502556
#[test]
503557
fn open_with_not_empty_newly_opened_fields() {
504558
let mut game_ptr = create_game(GameLevel::Beginner);
@@ -647,6 +701,14 @@ mod test {
647701
destroy_game(&mut game_ptr);
648702
}
649703

704+
#[test]
705+
#[should_panic(expected = "Error info ptr is null!")]
706+
fn toggle_with_nullptr_as_error_info_ptr() {
707+
let game_ptr = create_game(GameLevel::Beginner);
708+
let mut flag_result = FlagResult::AlreadyOpened;
709+
minesweeper_game_toggle_flag(game_ptr, 0, 0, &mut flag_result, std::ptr::null_mut());
710+
}
711+
650712
#[test]
651713
fn flag_opened() {
652714
let mut game_ptr = create_game(GameLevel::Beginner);
@@ -692,6 +754,14 @@ mod test {
692754
destroy_game(&mut game_ptr);
693755
}
694756

757+
#[test]
758+
#[should_panic(expected = "Error info ptr is null!")]
759+
fn get_width_with_nullptr_as_error_info_ptr() {
760+
let game_ptr = create_game(GameLevel::Beginner);
761+
let mut width = 0;
762+
minesweeper_game_get_width(game_ptr, &mut width, std::ptr::null_mut());
763+
}
764+
695765
#[test]
696766
fn get_height_with_nullptr_as_game() {
697767
let mut error_info = create_empty_error_info();
@@ -709,6 +779,14 @@ mod test {
709779
destroy_game(&mut game_ptr);
710780
}
711781

782+
#[test]
783+
#[should_panic(expected = "Error info ptr is null!")]
784+
fn get_height_with_nullptr_as_error_info_ptr() {
785+
let game_ptr = create_game(GameLevel::Beginner);
786+
let mut height = 0;
787+
minesweeper_game_get_height(game_ptr, &mut height, std::ptr::null_mut());
788+
}
789+
712790
#[test]
713791
fn get_elapsed_seconds_with_nullptr_as_game() {
714792
let mut error_info = create_empty_error_info();
@@ -725,4 +803,12 @@ mod test {
725803
assert_eq!(CError::NullPointerAsInput, error_info.error_code);
726804
destroy_game(&mut game_ptr);
727805
}
806+
807+
#[test]
808+
#[should_panic(expected = "Error info ptr is null!")]
809+
fn get_elapsed_seconds_with_nullptr_as_error_info_ptr() {
810+
let game_ptr = create_game(GameLevel::Beginner);
811+
let mut elapsed_seconds = 0;
812+
minesweeper_game_get_elapsed_seconds(game_ptr, &mut elapsed_seconds, std::ptr::null_mut());
813+
}
728814
}

0 commit comments

Comments
 (0)