Skip to content

Commit 2d546aa

Browse files
committed
transpile: Do not leak main argument strings
1 parent e686f1e commit 2d546aa

File tree

2 files changed

+105
-52
lines changed

2 files changed

+105
-52
lines changed

c2rust-transpile/src/translator/main_function.rs

Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! Rust.
55
66
use super::*;
7+
use c2rust_ast_builder::CaptureBy;
78
use failure::format_err;
89
use proc_macro2::{TokenStream, TokenTree};
910

@@ -53,45 +54,97 @@ impl<'c> Translation<'c> {
5354
if n >= 2 {
5455
// `argv` and `argc`
5556

56-
stmts.push(mk().local_stmt(Box::new(mk().local(
57-
mk().mutbl().ident_pat("args"),
58-
Some(mk().path_ty(vec![mk().path_segment_with_args(
57+
stmts.push(mk().local_stmt(Box::new({
58+
// ty = Vec<Vec<u8>>
59+
let ty = mk().path_ty(vec![mk().path_segment_with_args(
5960
"Vec",
60-
mk().angle_bracketed_args(vec![
61-
mk().mutbl().ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"])),
62-
]),
63-
)])),
64-
Some(mk().call_expr(mk().path_expr(vec!["Vec", "new"]), vec![])),
65-
))));
66-
stmts.push(mk().semi_stmt(mk().for_expr(
67-
mk().ident_pat("arg"),
68-
mk().call_expr(args_fn, vec![]),
69-
mk().block(vec![mk().semi_stmt(mk().method_call_expr(
70-
mk().path_expr(vec!["args"]),
71-
"push",
72-
vec![mk().method_call_expr(
73-
mk().method_call_expr(
74-
mk().call_expr(
75-
// TODO(kkysen) change `"std"` to `"alloc"` after `#![feature(alloc_c_string)]` is stabilized in `1.63.0`
76-
mk().abs_path_expr(vec!["std", "ffi", "CString", "new"]),
77-
vec![mk().path_expr(vec!["arg"])],
78-
),
79-
"expect",
80-
vec![mk().lit_expr("Failed to convert argument into CString.")],
81-
),
82-
"into_raw",
61+
mk().angle_bracketed_args(vec![mk().path_ty(vec![mk()
62+
.path_segment_with_args(
63+
"Vec",
64+
mk().angle_bracketed_args(vec![mk().ident_ty("u8")]),
65+
)])]),
66+
)]);
67+
// map_arg = |arg| {
68+
// (::std::ffi::CString::new(arg))
69+
// .expect("Failed to convert argument into CString.")
70+
// .into_bytes_with_nul()
71+
// }
72+
let cstring_call = mk().call_expr(
73+
// TODO(kkysen) change `"std"` to `"alloc"` after `#![feature(alloc_c_string)]` is stabilized in `1.63.0`
74+
mk().abs_path_expr(vec!["std", "ffi", "CString", "new"]),
75+
vec![mk().path_expr(vec!["arg"])],
76+
);
77+
let expect_arg = mk().lit_expr("Failed to convert argument into CString.");
78+
let map_arg = mk().closure_expr(
79+
CaptureBy::Ref,
80+
Movability::Movable,
81+
vec![mk().ident_pat("arg")],
82+
ReturnType::Default,
83+
mk().method_chain_expr(
84+
cstring_call,
85+
vec![
86+
(mk().path_segment("expect"), vec![expect_arg]),
87+
(mk().path_segment("into_bytes_with_nul"), vec![]),
88+
],
89+
),
90+
);
91+
// init = args_fn
92+
// .map(map_arg)
93+
// .collect();
94+
let init = mk().method_chain_expr(
95+
mk().call_expr(args_fn, vec![]),
96+
vec![
97+
(mk().path_segment("map"), vec![map_arg]),
98+
(mk().path_segment("collect"), vec![]),
99+
],
100+
);
101+
mk().local(mk().mutbl().ident_pat("args_strings"), Some(ty), Some(init))
102+
})));
103+
104+
stmts.push(mk().local_stmt(Box::new({
105+
// ty = Vec<*mut ::core::ffi::c_char>
106+
let ty = mk().path_ty(vec![mk().path_segment_with_args(
107+
"Vec",
108+
mk().angle_bracketed_args(vec![mk()
109+
.mutbl()
110+
.ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"]))]),
111+
)]);
112+
// map_arg = |arg| arg.as_mut_ptr() as *mut ::core::ffi::c_char
113+
let map_arg = mk().closure_expr(
114+
CaptureBy::Ref,
115+
Movability::Movable,
116+
vec![mk().ident_pat("arg")],
117+
ReturnType::Default,
118+
mk().cast_expr(
119+
mk().method_call_expr(mk().ident_expr("arg"), "as_mut_ptr", vec![]),
120+
mk().mutbl()
121+
.ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"])),
122+
),
123+
);
124+
// chain_arg = ::core::iter::once(::core::ptr::null_mut())
125+
let chain_arg = mk().call_expr(
126+
mk().abs_path_expr(vec!["core", "iter", "once"]),
127+
vec![mk().call_expr(
128+
mk().abs_path_expr(vec!["core", "ptr", "null_mut"]),
83129
vec![],
84130
)],
85-
))]),
86-
None::<Ident>,
87-
)));
88-
stmts.push(mk().semi_stmt(mk().method_call_expr(
89-
mk().path_expr(vec!["args"]),
90-
"push",
91-
vec![
92-
mk().call_expr(mk().abs_path_expr(vec!["core", "ptr", "null_mut"]), vec![]),
93-
],
94-
)));
131+
);
132+
// init = args_strings
133+
// .iter_mut()
134+
// .map(map_arg)
135+
// .chain(chain_arg)
136+
// .collect()
137+
let init = mk().method_chain_expr(
138+
mk().ident_expr("args_strings"),
139+
vec![
140+
(mk().path_segment("iter_mut"), vec![]),
141+
(mk().path_segment("map"), vec![map_arg]),
142+
(mk().path_segment("chain"), vec![chain_arg]),
143+
(mk().path_segment("collect"), vec![]),
144+
],
145+
);
146+
mk().local(mk().mutbl().ident_pat("args_ptrs"), Some(ty), Some(init))
147+
})));
95148

96149
let argc_ty: Box<Type> = match self.ast_context.index(parameters[0]).kind {
97150
CDeclKind::Variable { ref typ, .. } => self.convert_type(typ.ctype),
@@ -105,8 +158,7 @@ impl<'c> Translation<'c> {
105158
"Cannot find type of 'argv' argument in main function",
106159
)),
107160
}?;
108-
109-
let args = mk().ident_expr("args");
161+
let args = mk().ident_expr("args_ptrs");
110162
let argc = mk().binary_expr(
111163
BinOp::Sub(Default::default()),
112164
mk().method_call_expr(args.clone(), "len", no_args.clone()),

c2rust-transpile/tests/snapshots/snapshots__transpile@main.c.snap

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@ unsafe fn main_0(
1919
return 0 as ::core::ffi::c_int;
2020
}
2121
pub fn main() {
22-
let mut args: Vec<*mut ::core::ffi::c_char> = Vec::new();
23-
for arg in ::std::env::args() {
24-
args.push(
22+
let mut args_strings: Vec<Vec<u8>> = ::std::env::args()
23+
.map(|arg| {
2524
::std::ffi::CString::new(arg)
2625
.expect("Failed to convert argument into CString.")
27-
.into_raw(),
28-
);
29-
}
30-
args.push(::core::ptr::null_mut());
26+
.into_bytes_with_nul()
27+
})
28+
.collect();
29+
let mut args_ptrs: Vec<*mut ::core::ffi::c_char> = args_strings
30+
.iter_mut()
31+
.map(|arg| arg.as_mut_ptr() as *mut ::core::ffi::c_char)
32+
.chain(::core::iter::once(::core::ptr::null_mut()))
33+
.collect();
3134
let mut vars: Vec<*mut ::core::ffi::c_char> = Vec::new();
3235
for (var_name, var_value) in ::std::env::vars() {
3336
let var: String = format!("{}={}", var_name, var_value);
@@ -39,12 +42,10 @@ pub fn main() {
3942
}
4043
vars.push(::core::ptr::null_mut());
4144
unsafe {
42-
::std::process::exit(
43-
main_0(
44-
(args.len() - 1) as ::core::ffi::c_int,
45-
args.as_mut_ptr() as *mut *mut ::core::ffi::c_char,
46-
vars.as_mut_ptr() as *mut *mut ::core::ffi::c_char,
47-
) as i32,
48-
)
45+
::std::process::exit(main_0(
46+
(args_ptrs.len() - 1) as ::core::ffi::c_int,
47+
args_ptrs.as_mut_ptr() as *mut *mut ::core::ffi::c_char,
48+
vars.as_mut_ptr() as *mut *mut ::core::ffi::c_char,
49+
) as i32)
4950
}
5051
}

0 commit comments

Comments
 (0)