Skip to content

Commit d230164

Browse files
authored
Add errno rule (#128)
1 parent 7791f22 commit d230164

8 files changed

Lines changed: 147 additions & 0 deletions

File tree

cpp2rust/compat/errno.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) 2022-present INESC-ID.
2+
// Distributed under the MIT license that can be found in the LICENSE file.
3+
4+
#include_next <errno.h>
5+
6+
#undef errno
7+
8+
int *cpp2rust_errno(void);
9+
10+
#define errno (*cpp2rust_errno())

libcc2rs/src/compat.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ unsafe extern "C" {
1111
#[cfg(target_os = "macos")]
1212
#[link_name = "malloc_size"]
1313
fn platform_malloc_size(ptr: *const c_void) -> usize;
14+
15+
#[cfg(target_os = "linux")]
16+
#[link_name = "__errno_location"]
17+
fn platform_errno_location() -> *mut i32;
18+
19+
#[cfg(target_os = "macos")]
20+
#[link_name = "__error"]
21+
fn platform_errno_location() -> *mut i32;
1422
}
1523

1624
/// # Safety
@@ -28,3 +36,10 @@ pub unsafe fn malloc_usable_size(ptr: *mut c_void) -> usize {
2836
unsafe { platform_malloc_size(ptr as *const c_void) }
2937
}
3038
}
39+
40+
/// # Safety
41+
///
42+
/// Invokes the platform specific errno.
43+
pub unsafe fn cpp2rust_errno() -> *mut i32 {
44+
unsafe { platform_errno_location() }
45+
}

rules/errno/ir_unsafe.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"f1": {
3+
"body": [
4+
{
5+
"text": "libcc2rs::cpp2rust_errno()"
6+
}
7+
],
8+
"return_type": {
9+
"type": "*mut i32",
10+
"is_unsafe_pointer": true
11+
}
12+
}
13+
}

rules/errno/src.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) 2022-present INESC-ID.
2+
// Distributed under the MIT license that can be found in the LICENSE file.
3+
4+
#include <errno.h>
5+
6+
int *f1(void) { return cpp2rust_errno(); }

rules/errno/tgt_unsafe.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) 2022-present INESC-ID.
2+
// Distributed under the MIT license that can be found in the LICENSE file.
3+
4+
unsafe fn f1() -> *mut i32 {
5+
libcc2rs::cpp2rust_errno()
6+
}

rules/src/modules.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ pub mod cstring_tgt_unsafe;
3434
pub mod deque_tgt_refcount;
3535
#[path = r#"../deque/tgt_unsafe.rs"#]
3636
pub mod deque_tgt_unsafe;
37+
#[path = r#"../errno/tgt_unsafe.rs"#]
38+
pub mod errno_tgt_unsafe;
3739
#[path = r#"../fstream/tgt_refcount.rs"#]
3840
pub mod fstream_tgt_refcount;
3941
#[path = r#"../fstream/tgt_unsafe.rs"#]

tests/unit/errno.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// no-compile: refcount
2+
#include <assert.h>
3+
#include <errno.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
8+
static void test_errno(void) {
9+
errno = 0;
10+
assert(errno == 0);
11+
errno = 42;
12+
assert(errno == 42);
13+
int saved = errno;
14+
assert(saved == 42);
15+
errno = 0;
16+
}
17+
18+
static void test_errno_preserved_across_strdup(void) {
19+
errno = 99;
20+
char *d = strdup("hello");
21+
assert(d != NULL);
22+
assert(errno == 99);
23+
free(d);
24+
errno = 0;
25+
}
26+
27+
static void test_errno_from_fseek(void) {
28+
errno = 0;
29+
int r = fseek(stdin, 0, SEEK_SET);
30+
assert(r == -1);
31+
assert(errno == ESPIPE);
32+
errno = 0;
33+
}
34+
35+
int main(void) {
36+
test_errno();
37+
test_errno_preserved_across_strdup();
38+
test_errno_from_fseek();
39+
return 0;
40+
}

tests/unit/out/unsafe/errno.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub unsafe fn test_errno_0() {
10+
(*libcc2rs::cpp2rust_errno()) = 0;
11+
assert!(((((*libcc2rs::cpp2rust_errno()) == (0)) as i32) != 0));
12+
(*libcc2rs::cpp2rust_errno()) = 42;
13+
assert!(((((*libcc2rs::cpp2rust_errno()) == (42)) as i32) != 0));
14+
let mut saved: i32 = (*libcc2rs::cpp2rust_errno());
15+
assert!(((((saved) == (42)) as i32) != 0));
16+
(*libcc2rs::cpp2rust_errno()) = 0;
17+
}
18+
pub unsafe fn test_errno_preserved_across_strdup_1() {
19+
(*libcc2rs::cpp2rust_errno()) = 99;
20+
let mut d: *mut u8 =
21+
libc::strdup((b"hello\0".as_ptr().cast_mut()).cast_const() as *const i8) as *mut u8;
22+
assert!((((!((d).is_null())) as i32) != 0));
23+
assert!(((((*libcc2rs::cpp2rust_errno()) == (99)) as i32) != 0));
24+
libc::free((d as *mut u8 as *mut ::libc::c_void));
25+
(*libcc2rs::cpp2rust_errno()) = 0;
26+
}
27+
pub unsafe fn test_errno_from_fseek_2() {
28+
(*libcc2rs::cpp2rust_errno()) = 0;
29+
let mut r: i32 = if (match 0 {
30+
0 => (*libcc2rs::cin_unsafe()).seek(std::io::SeekFrom::Start(0_i64 as u64)),
31+
1 => (*libcc2rs::cin_unsafe()).seek(std::io::SeekFrom::Current(0_i64)),
32+
2 => (*libcc2rs::cin_unsafe()).seek(std::io::SeekFrom::End(0_i64)),
33+
_ => Err(std::io::Error::other("unsupported whence for fseek.")),
34+
})
35+
.is_ok()
36+
{
37+
0
38+
} else {
39+
-1
40+
};
41+
assert!(((((r) == (-1_i32)) as i32) != 0));
42+
assert!(((((*libcc2rs::cpp2rust_errno()) == (29)) as i32) != 0));
43+
(*libcc2rs::cpp2rust_errno()) = 0;
44+
}
45+
pub fn main() {
46+
unsafe {
47+
std::process::exit(main_0() as i32);
48+
}
49+
}
50+
unsafe fn main_0() -> i32 {
51+
(unsafe { test_errno_0() });
52+
(unsafe { test_errno_preserved_across_strdup_1() });
53+
(unsafe { test_errno_from_fseek_2() });
54+
return 0;
55+
}

0 commit comments

Comments
 (0)