From 8a420ebc3efa1b1bc4137c42ed20e3a0879778b4 Mon Sep 17 00:00:00 2001 From: Toru Ogawa Date: Sun, 14 Aug 2022 11:32:52 +0900 Subject: [PATCH 1/4] Support `va_copy` with a member of a struct pointer. --- c2rust-transpile/src/translator/variadic.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/c2rust-transpile/src/translator/variadic.rs b/c2rust-transpile/src/translator/variadic.rs index 9a5700bf8e..a10414876f 100644 --- a/c2rust-transpile/src/translator/variadic.rs +++ b/c2rust-transpile/src/translator/variadic.rs @@ -58,6 +58,22 @@ impl<'c> Translation<'c> { Some(va_id) } + // struct-based va_list (e.g. x86_64) where va_list is accessed as a member of a struct pointer + fn match_vastart_struct_pointer_member( + ast_context: &TypedAstContext, + expr: CExprId, + ) -> Option { + match_or! { [ast_context[expr].kind] + CExprKind::ImplicitCast(_, me, _, _, _) => me } + match_or! { [ast_context[me].kind] + CExprKind::Member(_, ie, _, _, _) => ie } + match_or! { [ast_context[ie].kind] + CExprKind::ImplicitCast(_, e, _, _, _) => e } + match_or! { [ast_context[e].kind] + CExprKind::DeclRef(_, va_id, _) => va_id } + Some(va_id) + } + // char pointer-based va_list (e.g. x86) fn match_vastart_pointer(ast_context: &TypedAstContext, expr: CExprId) -> Option { match_or! { [ast_context[expr].kind] @@ -68,6 +84,7 @@ impl<'c> Translation<'c> { match_vastart_struct(&self.ast_context, expr) .or_else(|| match_vastart_pointer(&self.ast_context, expr)) .or_else(|| match_vastart_struct_member(&self.ast_context, expr)) + .or_else(|| match_vastart_struct_pointer_member(&self.ast_context, expr)) } pub fn match_vaend(&self, expr: CExprId) -> Option { From 787631b4f2badc12f8208c356c72fdc73ed8fd2f Mon Sep 17 00:00:00 2001 From: Toru Ogawa Date: Tue, 16 Aug 2022 23:14:37 +0900 Subject: [PATCH 2/4] Add a test for `va_*` with a member of a struct pointer. --- tests/items/src/test_varargs.rs | 12 +++++++++++- tests/items/src/varargs.c | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/items/src/test_varargs.rs b/tests/items/src/test_varargs.rs index fb697dfcbb..5ccb21db49 100644 --- a/tests/items/src/test_varargs.rs +++ b/tests/items/src/test_varargs.rs @@ -2,7 +2,7 @@ use crate::varargs::{ rust_call_printf, rust_call_vprintf, rust_my_printf, rust_restart_valist, rust_sample_stddev, - rust_simple_vacopy, rust_valist_struct_member, + rust_simple_vacopy, rust_valist_struct_member, rust_valist_struct_pointer_member, }; use libc::c_char; @@ -20,6 +20,8 @@ extern "C" { fn valist_struct_member(_: *const c_char, ...); + fn valist_struct_pointer_member(_: *const c_char, ...); + fn restart_valist(_: *const c_char, ...); fn sample_stddev(count: i32, ...) -> f64; @@ -69,6 +71,14 @@ pub fn test_valist_struct_member() { } } +pub fn test_valist_struct_pointer_member() { + let fmt_str = CString::new("%d, %f\n").unwrap(); + unsafe { + valist_struct_pointer_member(fmt_str.as_ptr(), 10, 1.5); + rust_valist_struct_pointer_member(fmt_str.as_ptr(), 10, 1.5); + } +} + pub fn test_restart_valist() { let fmt_str = CString::new("%d, %f\n").unwrap(); unsafe { diff --git a/tests/items/src/varargs.c b/tests/items/src/varargs.c index 1546ec7543..1e62fa9c28 100644 --- a/tests/items/src/varargs.c +++ b/tests/items/src/varargs.c @@ -80,6 +80,16 @@ void valist_struct_member(const char *fmt, ...) { va_end(thestruct.args); } +// pattern first seen in graphviz (sftable.c) +void valist_struct_pointer_member(const char *fmt, ...) { + struct vastruct thestruct; + struct vastruct *pointer = &thestruct; + + va_start(pointer->args, fmt); + vprintf(fmt, pointer->args); + va_end(pointer->args); +} + // mirrors pattern from json-c's sprintbuf void restart_valist(const char *fmt, ...) { va_list ap; From 98050bcced9b7a4ad5c414305bb072a230034f4f Mon Sep 17 00:00:00 2001 From: Toru Ogawa Date: Wed, 17 Aug 2022 08:17:58 +0900 Subject: [PATCH 3/4] Document the reason why this new `match_vastart_struct_pointer_member` function was added (transpiling `graphviz`), similarly to the other similar function. Co-authored-by: Khyber Sen --- c2rust-transpile/src/translator/variadic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/c2rust-transpile/src/translator/variadic.rs b/c2rust-transpile/src/translator/variadic.rs index a10414876f..3e8bb09008 100644 --- a/c2rust-transpile/src/translator/variadic.rs +++ b/c2rust-transpile/src/translator/variadic.rs @@ -59,6 +59,7 @@ impl<'c> Translation<'c> { } // struct-based va_list (e.g. x86_64) where va_list is accessed as a member of a struct pointer + // supporting this pattern is necessary to transpile [graphviz](https://gitlab.com/graphviz/graphviz/-/blob/5.0.0/lib/sfio/sftable.c#L321) fn match_vastart_struct_pointer_member( ast_context: &TypedAstContext, expr: CExprId, From ff76f3c819abfec85e2333a540d3ac119114c5b6 Mon Sep 17 00:00:00 2001 From: Toru Ogawa Date: Wed, 17 Aug 2022 08:28:06 +0900 Subject: [PATCH 4/4] Also check `va_copy` works with a member of a struct pointer. --- tests/items/src/varargs.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/items/src/varargs.c b/tests/items/src/varargs.c index 1e62fa9c28..3dc3745325 100644 --- a/tests/items/src/varargs.c +++ b/tests/items/src/varargs.c @@ -73,21 +73,27 @@ struct vastruct { // pattern first seen in apache (util_script.c) void valist_struct_member(const char *fmt, ...) { - struct vastruct thestruct; - - va_start(thestruct.args, fmt); - vprintf(fmt, thestruct.args); - va_end(thestruct.args); + struct vastruct a, b; + + va_start(a.args, fmt); + va_copy(b.args, a.args); + vprintf(fmt, a.args); + vprintf(fmt, b.args); + va_end(a.args); + va_end(b.args); } // pattern first seen in graphviz (sftable.c) void valist_struct_pointer_member(const char *fmt, ...) { - struct vastruct thestruct; - struct vastruct *pointer = &thestruct; - - va_start(pointer->args, fmt); - vprintf(fmt, pointer->args); - va_end(pointer->args); + struct vastruct a, b; + struct vastruct *p = &a, *q = &b; + + va_start(p->args, fmt); + va_copy(q->args, p->args); + vprintf(fmt, p->args); + vprintf(fmt, q->args); + va_end(p->args); + va_end(q->args); } // mirrors pattern from json-c's sprintbuf