Skip to content

Commit ebbf77d

Browse files
authored
Translate offsetof in refcount (#255)
Refcount structs don't have the same layout as C structs. Don't translate offsetof as std::mem::offset_of, instead let clang evaluate the offset and hardcode it in the generated rust code. ByteRepr takes care of using it correctly.
1 parent f5c2b67 commit ebbf77d

5 files changed

Lines changed: 152 additions & 21 deletions

File tree

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,14 @@ bool ConverterRefCount::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) {
417417
return false;
418418
}
419419

420+
bool ConverterRefCount::VisitOffsetOfExpr(clang::OffsetOfExpr *expr) {
421+
clang::Expr::EvalResult result;
422+
ENSURE(expr->EvaluateAsInt(result, ctx_));
423+
StrCat(std::format("{}_usize", result.Val.getInt().getZExtValue()));
424+
computed_expr_type_ = ComputedExprType::FreshValue;
425+
return false;
426+
}
427+
420428
void ConverterRefCount::ConvertOrdAndPartialOrdTraits(
421429
const clang::CXXRecordDecl *decl, const clang::FunctionDecl *op) {
422430
std::string first_branch, second_branch, first_return, second_return;

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class ConverterRefCount final : public Converter {
2828

2929
bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl) override;
3030

31+
bool VisitOffsetOfExpr(clang::OffsetOfExpr *expr) override;
32+
3133
void EmitRustUnion(clang::RecordDecl *decl) override;
3234

3335
bool EmitsReprCForRecords() const override { return false; }

‎tests/unit/offsetof.cpp‎

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
1-
// no-compile: refcount
21
#include <assert.h>
32
#include <stddef.h>
43
#include <stdint.h>
4+
#include <string.h>
55

66
struct Layout {
77
uint8_t a;
88
uint32_t b;
99
uint16_t c;
1010
};
1111

12-
struct Inner {
13-
uint16_t x;
14-
uint32_t y;
15-
};
16-
17-
struct Outer {
18-
uint8_t pad;
19-
struct Inner inner;
12+
struct Frame {
13+
uint16_t tag;
14+
char body[64];
2015
};
2116

2217
int main(void) {
2318
assert(offsetof(struct Layout, a) == 0);
2419
assert(offsetof(struct Layout, b) == 4);
2520
assert(offsetof(struct Layout, c) == 8);
2621

27-
assert(offsetof(struct Outer, inner.y) == 8);
28-
2922
struct Layout v = {0};
3023
v.b = 0xDEADBEEF;
3124
unsigned char *base = (unsigned char *)&v;
3225
uint32_t *bp = (uint32_t *)(base + offsetof(struct Layout, b));
3326
assert(*bp == 0xDEADBEEF);
3427

28+
*(uint32_t *)(base + offsetof(struct Layout, b)) = 0x12345678;
29+
assert(v.b == 0x12345678);
30+
31+
const char *text = "example-body";
32+
size_t len = strlen(text) + 1;
33+
size_t total = offsetof(struct Frame, body) + len;
34+
assert(total == 2 + len);
35+
3536
return 0;
3637
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
#[derive(Default)]
10+
pub struct Layout {
11+
pub a: Value<u8>,
12+
pub b: Value<u32>,
13+
pub c: Value<u16>,
14+
}
15+
impl Clone for Layout {
16+
fn clone(&self) -> Self {
17+
let mut this = Self {
18+
a: Rc::new(RefCell::new((*self.a.borrow()))),
19+
b: Rc::new(RefCell::new((*self.b.borrow()))),
20+
c: Rc::new(RefCell::new((*self.c.borrow()))),
21+
};
22+
this
23+
}
24+
}
25+
impl ByteRepr for Layout {
26+
fn byte_size() -> usize {
27+
12
28+
}
29+
fn to_bytes(&self, buf: &mut [u8]) {
30+
(*self.a.borrow()).to_bytes(&mut buf[0..1]);
31+
(*self.b.borrow()).to_bytes(&mut buf[4..8]);
32+
(*self.c.borrow()).to_bytes(&mut buf[8..10]);
33+
}
34+
fn from_bytes(buf: &[u8]) -> Self {
35+
Self {
36+
a: Rc::new(RefCell::new(<u8>::from_bytes(&buf[0..1]))),
37+
b: Rc::new(RefCell::new(<u32>::from_bytes(&buf[4..8]))),
38+
c: Rc::new(RefCell::new(<u16>::from_bytes(&buf[8..10]))),
39+
}
40+
}
41+
}
42+
#[derive()]
43+
pub struct Frame {
44+
pub tag: Value<u16>,
45+
pub body: Value<Box<[u8]>>,
46+
}
47+
impl Clone for Frame {
48+
fn clone(&self) -> Self {
49+
let mut this = Self {
50+
tag: Rc::new(RefCell::new((*self.tag.borrow()))),
51+
body: Rc::new(RefCell::new((*self.body.borrow()).clone())),
52+
};
53+
this
54+
}
55+
}
56+
impl Default for Frame {
57+
fn default() -> Self {
58+
Frame {
59+
tag: <Value<u16>>::default(),
60+
body: Rc::new(RefCell::new(
61+
(0..64).map(|_| <u8>::default()).collect::<Box<[u8]>>(),
62+
)),
63+
}
64+
}
65+
}
66+
impl ByteRepr for Frame {
67+
fn byte_size() -> usize {
68+
66
69+
}
70+
fn to_bytes(&self, buf: &mut [u8]) {
71+
(*self.tag.borrow()).to_bytes(&mut buf[0..2]);
72+
(*self.body.borrow()).to_bytes(&mut buf[2..66]);
73+
}
74+
fn from_bytes(buf: &[u8]) -> Self {
75+
Self {
76+
tag: Rc::new(RefCell::new(<u16>::from_bytes(&buf[0..2]))),
77+
body: Rc::new(RefCell::new(<Box<[u8]>>::from_bytes(&buf[2..66]))),
78+
}
79+
}
80+
}
81+
pub fn main() {
82+
std::process::exit(main_0());
83+
}
84+
fn main_0() -> i32 {
85+
assert!((0_usize == 0_usize));
86+
assert!((4_usize == 4_usize));
87+
assert!((8_usize == 8_usize));
88+
let v: Value<Layout> = Rc::new(RefCell::new(Layout {
89+
a: Rc::new(RefCell::new(0_u8)),
90+
b: Rc::new(RefCell::new(<u32>::default())),
91+
c: Rc::new(RefCell::new(<u16>::default())),
92+
}));
93+
(*(*v.borrow()).b.borrow_mut()) = 3735928559_u32;
94+
let base: Value<Ptr<u8>> = Rc::new(RefCell::new((v.as_pointer()).reinterpret_cast::<u8>()));
95+
let bp: Value<Ptr<u32>> = Rc::new(RefCell::new(
96+
((*base.borrow()).offset((4_usize) as isize)).reinterpret_cast::<u32>(),
97+
));
98+
assert!((((*bp.borrow()).read()) == 3735928559_u32));
99+
((*base.borrow()).offset((4_usize) as isize))
100+
.reinterpret_cast::<u32>()
101+
.write(305419896_u32);
102+
assert!(((*(*v.borrow()).b.borrow()) == 305419896_u32));
103+
let text: Value<Ptr<u8>> = Rc::new(RefCell::new(Ptr::from_string_literal(b"example-body")));
104+
let len: Value<usize> = Rc::new(RefCell::new(
105+
((*text.borrow()).to_string_iterator().count()).wrapping_add(1_usize),
106+
));
107+
let total: Value<usize> = Rc::new(RefCell::new(
108+
((2_usize as u64).wrapping_add(((*len.borrow()) as u64)) as usize),
109+
));
110+
assert!(((*total.borrow()) == (2_usize).wrapping_add((*len.borrow()))));
111+
return 0;
112+
}

‎tests/unit/out/unsafe/offsetof.rs‎

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ pub struct Layout {
1414
pub c: u16,
1515
}
1616
#[repr(C)]
17-
#[derive(Copy, Clone, Default)]
18-
pub struct Inner {
19-
pub x: u16,
20-
pub y: u32,
17+
#[derive(Copy, Clone)]
18+
pub struct Frame {
19+
pub tag: u16,
20+
pub body: [libc::c_char; 64],
2121
}
22-
#[repr(C)]
23-
#[derive(Copy, Clone, Default)]
24-
pub struct Outer {
25-
pub pad: u8,
26-
pub inner: Inner,
22+
impl Default for Frame {
23+
fn default() -> Self {
24+
Frame {
25+
tag: 0_u16,
26+
body: [(0 as libc::c_char); 64],
27+
}
28+
}
2729
}
2830
pub fn main() {
2931
unsafe {
@@ -34,7 +36,6 @@ unsafe fn main_0() -> i32 {
3436
assert!(((::std::mem::offset_of!(Layout, a)) == (0_usize)));
3537
assert!(((::std::mem::offset_of!(Layout, b)) == (4_usize)));
3638
assert!(((::std::mem::offset_of!(Layout, c)) == (8_usize)));
37-
assert!(((::std::mem::offset_of!(Outer, inner.y)) == (8_usize)));
3839
let mut v: Layout = Layout {
3940
a: 0_u8,
4041
b: 0_u32,
@@ -45,5 +46,12 @@ unsafe fn main_0() -> i32 {
4546
let mut bp: *mut u32 =
4647
((base.offset((::std::mem::offset_of!(Layout, b)) as isize)) as *mut u32);
4748
assert!(((*bp) == (3735928559_u32)));
49+
(*((base.offset((::std::mem::offset_of!(Layout, b)) as isize)) as *mut u32)) = 305419896_u32;
50+
assert!(((v.b) == (305419896_u32)));
51+
let mut text: *const libc::c_char = c"example-body".as_ptr();
52+
let mut len: usize = (libc::strlen(text)).wrapping_add(1_usize);
53+
let mut total: usize =
54+
((::std::mem::offset_of!(Frame, body) as u64).wrapping_add((len as u64)) as usize);
55+
assert!(((total) == ((2_usize).wrapping_add(len))));
4856
return 0;
4957
}

0 commit comments

Comments
 (0)