Skip to content

Commit 6927cf5

Browse files
committed
Fix race condition in clang_macro_fallback
1 parent 76920aa commit 6927cf5

File tree

7 files changed

+43
-66
lines changed

7 files changed

+43
-66
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ regex = { workspace = true, features = ["std", "unicode-perl"] }
4141
rustc-hash.workspace = true
4242
shlex.workspace = true
4343
syn = { workspace = true, features = ["full", "extra-traits", "visit-mut"] }
44+
tempfile.workspace = true
4445

4546
[features]
4647
default = ["logging", "prettyplease", "runtime"]

bindgen/clang.rs

+24-21
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use crate::ir::context::BindgenContext;
88
use clang_sys::*;
99
use std::cmp;
10+
use std::path::{Path, PathBuf};
11+
use tempfile::TempDir;
1012

1113
use std::ffi::{CStr, CString};
1214
use std::fmt;
@@ -1822,12 +1824,15 @@ impl TranslationUnit {
18221824
/// Parse a source file into a translation unit.
18231825
pub(crate) fn parse(
18241826
ix: &Index,
1825-
file: &str,
1827+
file: Option<&Path>,
18261828
cmd_args: &[Box<str>],
18271829
unsaved: &[UnsavedFile],
18281830
opts: CXTranslationUnit_Flags,
18291831
) -> Option<TranslationUnit> {
1830-
let fname = CString::new(file).unwrap();
1832+
let fname = match file {
1833+
Some(file) => path_to_cstring(file),
1834+
None => CString::new(vec![]).unwrap(),
1835+
};
18311836
let _c_args: Vec<CString> = cmd_args
18321837
.iter()
18331838
.map(|s| CString::new(s.as_bytes()).unwrap())
@@ -1879,10 +1884,8 @@ impl TranslationUnit {
18791884
}
18801885

18811886
/// Save a translation unit to the given file.
1882-
pub(crate) fn save(&mut self, file: &str) -> Result<(), CXSaveError> {
1883-
let Ok(file) = CString::new(file) else {
1884-
return Err(CXSaveError_Unknown);
1885-
};
1887+
pub(crate) fn save(&mut self, file: &Path) -> Result<(), CXSaveError> {
1888+
let file = path_to_cstring(file);
18861889
let ret = unsafe {
18871890
clang_saveTranslationUnit(
18881891
self.x,
@@ -1913,8 +1916,9 @@ impl Drop for TranslationUnit {
19131916

19141917
/// Translation unit used for macro fallback parsing
19151918
pub(crate) struct FallbackTranslationUnit {
1916-
file_path: String,
1917-
pch_path: String,
1919+
temp_dir: TempDir,
1920+
file_path: PathBuf,
1921+
pch_path: PathBuf,
19181922
idx: Box<Index>,
19191923
tu: TranslationUnit,
19201924
}
@@ -1928,8 +1932,9 @@ impl fmt::Debug for FallbackTranslationUnit {
19281932
impl FallbackTranslationUnit {
19291933
/// Create a new fallback translation unit
19301934
pub(crate) fn new(
1931-
file: String,
1932-
pch_path: String,
1935+
temp_dir: TempDir,
1936+
file: PathBuf,
1937+
pch_path: PathBuf,
19331938
c_args: &[Box<str>],
19341939
) -> Option<Self> {
19351940
// Create empty file
@@ -1943,12 +1948,13 @@ impl FallbackTranslationUnit {
19431948
let f_index = Box::new(Index::new(true, false));
19441949
let f_translation_unit = TranslationUnit::parse(
19451950
&f_index,
1946-
&file,
1951+
Some(&file),
19471952
c_args,
19481953
&[],
19491954
CXTranslationUnit_None,
19501955
)?;
19511956
Some(FallbackTranslationUnit {
1957+
temp_dir,
19521958
file_path: file,
19531959
pch_path,
19541960
tu: f_translation_unit,
@@ -1985,13 +1991,6 @@ impl FallbackTranslationUnit {
19851991
}
19861992
}
19871993

1988-
impl Drop for FallbackTranslationUnit {
1989-
fn drop(&mut self) {
1990-
let _ = std::fs::remove_file(&self.file_path);
1991-
let _ = std::fs::remove_file(&self.pch_path);
1992-
}
1993-
}
1994-
19951994
/// A diagnostic message generated while parsing a translation unit.
19961995
pub(crate) struct Diagnostic {
19971996
x: CXDiagnostic,
@@ -2032,9 +2031,9 @@ pub(crate) struct UnsavedFile {
20322031
}
20332032

20342033
impl UnsavedFile {
2035-
/// Construct a new unsaved file with the given `name` and `contents`.
2036-
pub(crate) fn new(name: &str, contents: &str) -> UnsavedFile {
2037-
let name = CString::new(name.as_bytes()).unwrap();
2034+
/// Construct a new unsaved file with the given `path` and `contents`.
2035+
pub(crate) fn new(path: &Path, contents: &str) -> UnsavedFile {
2036+
let name = path_to_cstring(path);
20382037
let contents = CString::new(contents.as_bytes()).unwrap();
20392038
let x = CXUnsavedFile {
20402039
Filename: name.as_ptr(),
@@ -2446,3 +2445,7 @@ impl TargetInfo {
24462445
}
24472446
}
24482447
}
2448+
2449+
fn path_to_cstring(path: &Path) -> CString {
2450+
CString::new(path.to_string_lossy().as_bytes()).unwrap()
2451+
}

bindgen/ir/context.rs

+16-21
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use std::cell::{Cell, RefCell};
3131
use std::collections::{BTreeSet, HashMap as StdHashMap};
3232
use std::mem;
3333
use std::path::Path;
34+
use tempfile::TempDir;
3435

3536
/// An identifier for some kind of IR item.
3637
#[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)]
@@ -555,7 +556,7 @@ impl BindgenContext {
555556

556557
clang::TranslationUnit::parse(
557558
&index,
558-
"",
559+
None,
559560
&options.clang_args,
560561
input_unsaved_files,
561562
parse_options,
@@ -2040,20 +2041,18 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20402041
&mut self,
20412042
) -> Option<&mut clang::FallbackTranslationUnit> {
20422043
if self.fallback_tu.is_none() {
2043-
let file = format!(
2044-
"{}/.macro_eval.c",
2045-
match self.options().clang_macro_fallback_build_dir {
2046-
Some(ref path) => path.as_os_str().to_str()?,
2047-
None => ".",
2048-
}
2049-
);
2044+
let temp_dir = TempDir::new().unwrap();
2045+
2046+
let file = temp_dir.path().join(".macro_eval.c");
20502047

20512048
let index = clang::Index::new(false, false);
20522049

20532050
let mut header_names_to_compile = Vec::new();
20542051
let mut header_paths = Vec::new();
20552052
let mut header_includes = Vec::new();
2056-
let single_header = self.options().input_headers.last().cloned()?;
2053+
let single_header =
2054+
Path::new(&self.options().input_headers.last()?.as_ref())
2055+
.to_owned();
20572056
for input_header in &self.options.input_headers
20582057
[..self.options.input_headers.len() - 1]
20592058
{
@@ -2072,14 +2071,9 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20722071
header_names_to_compile
20732072
.push(header_name.split(".h").next()?.to_string());
20742073
}
2075-
let pch = format!(
2076-
"{}/{}",
2077-
match self.options().clang_macro_fallback_build_dir {
2078-
Some(ref path) => path.as_os_str().to_str()?,
2079-
None => ".",
2080-
},
2081-
header_names_to_compile.join("-") + "-precompile.h.pch"
2082-
);
2074+
let pch = temp_dir
2075+
.path()
2076+
.join(header_names_to_compile.join("-") + "-precompile.h.pch");
20832077

20842078
let mut c_args = self.options.fallback_clang_args.clone();
20852079
c_args.push("-x".to_string().into_boxed_str());
@@ -2093,7 +2087,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20932087
}
20942088
let mut tu = clang::TranslationUnit::parse(
20952089
&index,
2096-
&single_header,
2090+
Some(&single_header),
20972091
&c_args,
20982092
&[],
20992093
clang_sys::CXTranslationUnit_ForSerialization,
@@ -2102,7 +2096,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
21022096

21032097
let mut c_args = vec![
21042098
"-include-pch".to_string().into_boxed_str(),
2105-
pch.clone().into_boxed_str(),
2099+
pch.to_string_lossy().into_owned().into_boxed_str(),
21062100
];
21072101
let mut skip_next = false;
21082102
for arg in self.options.fallback_clang_args.iter() {
@@ -2114,8 +2108,9 @@ If you encounter an error missing from this list, please file an issue or a PR!"
21142108
c_args.push(arg.clone())
21152109
}
21162110
}
2117-
self.fallback_tu =
2118-
Some(clang::FallbackTranslationUnit::new(file, pch, &c_args)?);
2111+
self.fallback_tu = Some(clang::FallbackTranslationUnit::new(
2112+
temp_dir, file, pch, &c_args,
2113+
)?);
21192114
}
21202115

21212116
self.fallback_tu.as_mut()

bindgen/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl Builder {
371371
std::mem::take(&mut self.options.input_header_contents)
372372
.into_iter()
373373
.map(|(name, contents)| {
374-
clang::UnsavedFile::new(name.as_ref(), contents.as_ref())
374+
clang::UnsavedFile::new((*name).as_ref(), contents.as_ref())
375375
})
376376
.collect::<Vec<_>>();
377377

bindgen/options/cli.rs

-5
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,6 @@ struct BindgenCommand {
459459
/// Enable fallback for clang macro parsing.
460460
#[arg(long)]
461461
clang_macro_fallback: bool,
462-
/// Set path for temporary files generated by fallback for clang macro parsing.
463-
#[arg(long)]
464-
clang_macro_fallback_build_dir: Option<PathBuf>,
465462
/// Use DSTs to represent structures with flexible array members.
466463
#[arg(long)]
467464
flexarray_dst: bool,
@@ -635,7 +632,6 @@ where
635632
override_abi,
636633
wrap_unsafe_ops,
637634
clang_macro_fallback,
638-
clang_macro_fallback_build_dir,
639635
flexarray_dst,
640636
with_derive_custom,
641637
with_derive_custom_struct,
@@ -932,7 +928,6 @@ where
932928
override_abi => |b, (abi, regex)| b.override_abi(abi, regex),
933929
wrap_unsafe_ops,
934930
clang_macro_fallback => |b, _| b.clang_macro_fallback(),
935-
clang_macro_fallback_build_dir,
936931
flexarray_dst,
937932
wrap_static_fns,
938933
wrap_static_fns_path,

bindgen/options/mod.rs

-18
Original file line numberDiff line numberDiff line change
@@ -2153,22 +2153,4 @@ options! {
21532153
},
21542154
as_args: "--clang-macro-fallback",
21552155
}
2156-
/// Path to use for temporary files created by clang macro fallback code like precompiled
2157-
/// headers.
2158-
clang_macro_fallback_build_dir: Option<PathBuf> {
2159-
methods: {
2160-
/// Set a path to a directory to which `.c` and `.h.pch` files should be written for the
2161-
/// purpose of using clang to evaluate macros that can't be easily parsed.
2162-
///
2163-
/// The default location for `.h.pch` files is the directory that the corresponding
2164-
/// `.h` file is located in. The default for the temporary `.c` file used for clang
2165-
/// parsing is the current working directory. Both of these defaults are overridden
2166-
/// by this option.
2167-
pub fn clang_macro_fallback_build_dir<P: AsRef<Path>>(mut self, path: P) -> Self {
2168-
self.options.clang_macro_fallback_build_dir = Some(path.as_ref().to_owned());
2169-
self
2170-
}
2171-
},
2172-
as_args: "--clang-macro-fallback-build-dir",
2173-
}
21742156
}

0 commit comments

Comments
 (0)