Skip to content

Commit 13b9aab

Browse files
committed
Track Context in ExecutionEngine and force drop order.
Fixes rust-lang#60
1 parent 7a9d738 commit 13b9aab

File tree

4 files changed

+89
-21
lines changed

4 files changed

+89
-21
lines changed

src/context.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ use std::rc::Rc;
2727
///
2828
/// A `Context` is not thread safe and cannot be shared across threads. Multiple `Context`s
2929
/// can, however, execute on different threads simultaneously according to the LLVM docs.
30-
#[derive(Debug, PartialEq, Eq)]
30+
///
31+
/// # Note
32+
///
33+
/// Cloning this object is essentially just a case of copying a couple pointers
34+
/// and incrementing one or two atomics, so this should be quite cheap to create
35+
/// copies. The underlying LLVM object will be automatically deallocated when
36+
/// there are no more references to it.
37+
#[derive(Clone, Debug, PartialEq, Eq)]
3138
pub struct Context {
3239
pub(crate) context: Rc<LLVMContextRef>,
3340
}

src/execution_engine.rs

+49-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use libc::c_int;
22
use llvm_sys::execution_engine::{LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, LLVMRunFunction, LLVMRunFunctionAsMain, LLVMDisposeExecutionEngine, LLVMGetFunctionAddress, LLVMAddModule, LLVMFindFunction, LLVMLinkInMCJIT, LLVMLinkInInterpreter, LLVMRemoveModule, LLVMGenericValueRef, LLVMFreeMachineCodeForFunction, LLVMAddGlobalMapping, LLVMRunStaticConstructors, LLVMRunStaticDestructors};
33

4+
use context::Context;
45
use module::Module;
56
use support::LLVMString;
67
use targets::TargetData;
@@ -13,6 +14,8 @@ use std::ffi::CString;
1314
use std::fmt::{self, Debug, Display, Formatter};
1415
use std::mem::{forget, zeroed, transmute_copy, size_of};
1516

17+
static EE_INNER_PANIC: &str = "ExecutionEngineInner should exist until Drop";
18+
1619
#[derive(Debug, PartialEq, Eq)]
1720
pub enum FunctionLookupError {
1821
JITNotEnabled,
@@ -83,19 +86,28 @@ impl Display for RemoveModuleError {
8386

8487
/// A reference-counted wrapper around LLVM's execution engine.
8588
///
89+
/// # Note
90+
///
8691
/// Cloning this object is essentially just a case of copying a couple pointers
8792
/// and incrementing one or two atomics, so this should be quite cheap to create
8893
/// copies. The underlying LLVM object will be automatically deallocated when
8994
/// there are no more references to it.
95+
// non_global_context is required to ensure last remaining Context ref will drop
96+
// after EE drop. execution_engine & target_data are an option for drop purposes
9097
#[derive(PartialEq, Eq, Debug)]
9198
pub struct ExecutionEngine {
92-
execution_engine: ExecEngineInner,
99+
non_global_context: Option<Context>,
100+
execution_engine: Option<ExecEngineInner>,
93101
target_data: Option<TargetData>,
94102
jit_mode: bool,
95103
}
96104

97105
impl ExecutionEngine {
98-
pub(crate) fn new(execution_engine: Rc<LLVMExecutionEngineRef>, jit_mode: bool) -> ExecutionEngine {
106+
pub(crate) fn new(
107+
execution_engine: Rc<LLVMExecutionEngineRef>,
108+
non_global_context: Option<Context>,
109+
jit_mode: bool,
110+
) -> ExecutionEngine {
99111
assert!(!execution_engine.is_null());
100112

101113
// REVIEW: Will we have to do this for LLVMGetExecutionEngineTargetMachine too?
@@ -104,12 +116,22 @@ impl ExecutionEngine {
104116
};
105117

106118
ExecutionEngine {
107-
execution_engine: ExecEngineInner(execution_engine),
119+
non_global_context,
120+
execution_engine: Some(ExecEngineInner(execution_engine)),
108121
target_data: Some(TargetData::new(target_data)),
109122
jit_mode: jit_mode,
110123
}
111124
}
112125

126+
pub(crate) fn execution_engine_rc(&self) -> &Rc<LLVMExecutionEngineRef> {
127+
&self.execution_engine.as_ref().expect(EE_INNER_PANIC).0
128+
}
129+
130+
#[inline]
131+
pub(crate) fn execution_engine_inner(&self) -> LLVMExecutionEngineRef {
132+
**self.execution_engine_rc()
133+
}
134+
113135
/// This function probably doesn't need to be called, but is here due to
114136
/// linking(?) requirements. Bad things happen if we don't provide it.
115137
pub fn link_in_mc_jit() {
@@ -169,7 +191,7 @@ impl ExecutionEngine {
169191
/// ```
170192
pub fn add_global_mapping(&self, value: &AnyValue, addr: usize) {
171193
unsafe {
172-
LLVMAddGlobalMapping(*self.execution_engine, value.as_value_ref(), addr as *mut _)
194+
LLVMAddGlobalMapping(self.execution_engine_inner(), value.as_value_ref(), addr as *mut _)
173195
}
174196
}
175197

@@ -192,7 +214,7 @@ impl ExecutionEngine {
192214
/// ```
193215
pub fn add_module(&self, module: &Module) -> Result<(), ()> {
194216
unsafe {
195-
LLVMAddModule(*self.execution_engine, module.module.get())
217+
LLVMAddModule(self.execution_engine_inner(), module.module.get())
196218
}
197219

198220
if module.owned_by_ee.borrow().is_some() {
@@ -206,7 +228,8 @@ impl ExecutionEngine {
206228

207229
pub fn remove_module(&self, module: &Module) -> Result<(), RemoveModuleError> {
208230
match *module.owned_by_ee.borrow() {
209-
Some(ref ee) if *ee.execution_engine != *self.execution_engine => return Err(RemoveModuleError::IncorrectModuleOwner),
231+
Some(ref ee) if ee.execution_engine_inner() != self.execution_engine_inner() =>
232+
return Err(RemoveModuleError::IncorrectModuleOwner),
210233
None => return Err(RemoveModuleError::ModuleNotOwned),
211234
_ => ()
212235
}
@@ -215,7 +238,7 @@ impl ExecutionEngine {
215238
let mut err_string = unsafe { zeroed() };
216239

217240
let code = unsafe {
218-
LLVMRemoveModule(*self.execution_engine, module.module.get(), &mut new_module, &mut err_string)
241+
LLVMRemoveModule(self.execution_engine_inner(), module.module.get(), &mut new_module, &mut err_string)
219242
};
220243

221244
if code == 1 {
@@ -300,7 +323,7 @@ impl ExecutionEngine {
300323

301324
let c_string = CString::new(fn_name).expect("Conversion to CString failed unexpectedly");
302325

303-
let address = LLVMGetFunctionAddress(*self.execution_engine, c_string.as_ptr());
326+
let address = LLVMGetFunctionAddress(self.execution_engine_inner(), c_string.as_ptr());
304327

305328
// REVIEW: Can also return 0 if no targets are initialized.
306329
// One option might be to set a (thread local?) global to true if any at all of the targets have been
@@ -313,8 +336,10 @@ impl ExecutionEngine {
313336
assert_eq!(size_of::<F>(), size_of::<usize>(),
314337
"The type `F` must have the same size as a function pointer");
315338

339+
let execution_engine = self.execution_engine.as_ref().expect(EE_INNER_PANIC);
340+
316341
Ok(JitFunction {
317-
_execution_engine: self.execution_engine.clone(),
342+
_execution_engine: execution_engine.clone(),
318343
inner: transmute_copy(&address),
319344
})
320345
}
@@ -337,7 +362,7 @@ impl ExecutionEngine {
337362
let mut function = unsafe { zeroed() };
338363

339364
let code = unsafe {
340-
LLVMFindFunction(*self.execution_engine, c_string.as_ptr(), &mut function)
365+
LLVMFindFunction(self.execution_engine_inner(), c_string.as_ptr(), &mut function)
341366
};
342367

343368
if code == 0 {
@@ -354,7 +379,7 @@ impl ExecutionEngine {
354379
.map(|val| val.generic_value)
355380
.collect();
356381

357-
let value = LLVMRunFunction(*self.execution_engine, function.as_value_ref(), args.len() as u32, args.as_mut_ptr()); // REVIEW: usize to u32 ok??
382+
let value = LLVMRunFunction(self.execution_engine_inner(), function.as_value_ref(), args.len() as u32, args.as_mut_ptr()); // REVIEW: usize to u32 ok??
358383

359384
GenericValue::new(value)
360385
}
@@ -368,26 +393,26 @@ impl ExecutionEngine {
368393

369394
let environment_variables = vec![]; // TODO: Support envp. Likely needs to be null terminated
370395

371-
LLVMRunFunctionAsMain(*self.execution_engine, function.as_value_ref(), raw_args.len() as u32, raw_args.as_ptr(), environment_variables.as_ptr()) // REVIEW: usize to u32 cast ok??
396+
LLVMRunFunctionAsMain(self.execution_engine_inner(), function.as_value_ref(), raw_args.len() as u32, raw_args.as_ptr(), environment_variables.as_ptr()) // REVIEW: usize to u32 cast ok??
372397
}
373398

374399
pub fn free_fn_machine_code(&self, function: &FunctionValue) {
375400
unsafe {
376-
LLVMFreeMachineCodeForFunction(*self.execution_engine, function.as_value_ref())
401+
LLVMFreeMachineCodeForFunction(self.execution_engine_inner(), function.as_value_ref())
377402
}
378403
}
379404

380405
// REVIEW: Is this actually safe?
381406
pub fn run_static_constructors(&self) {
382407
unsafe {
383-
LLVMRunStaticConstructors(*self.execution_engine)
408+
LLVMRunStaticConstructors(self.execution_engine_inner())
384409
}
385410
}
386411

387412
// REVIEW: Is this actually safe? Can you double destruct/free?
388413
pub fn run_static_destructors(&self) {
389414
unsafe {
390-
LLVMRunStaticDestructors(*self.execution_engine)
415+
LLVMRunStaticDestructors(self.execution_engine_inner())
391416
}
392417
}
393418
}
@@ -401,12 +426,20 @@ impl Drop for ExecutionEngine {
401426
.take()
402427
.expect("TargetData should always exist until Drop"),
403428
);
429+
430+
// We must ensure the EE gets dropped before its context does,
431+
// which is important in the case where the EE has the last
432+
// remaining reference to it context
433+
drop(self.execution_engine.take().expect(EE_INNER_PANIC));
404434
}
405435
}
406436

407437
impl Clone for ExecutionEngine {
408438
fn clone(&self) -> ExecutionEngine {
409-
ExecutionEngine::new(self.execution_engine.0.clone(), self.jit_mode)
439+
let context = self.non_global_context.clone();
440+
let execution_engine_rc = self.execution_engine_rc().clone();
441+
442+
ExecutionEngine::new(execution_engine_rc, context, self.jit_mode)
410443
}
411444
}
412445

src/module.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl Module {
138138

139139
Module {
140140
module: Cell::new(module),
141-
non_global_context: context.map(|ctx| Context::new(ctx.context.clone())),
141+
non_global_context: context.map(|ctx| ctx.clone()),
142142
owned_by_ee: RefCell::new(None),
143143
data_layout: RefCell::new(Some(Module::get_borrowed_data_layout(module))),
144144
}
@@ -425,7 +425,8 @@ impl Module {
425425
return Err(LLVMString::new(err_string));
426426
}
427427

428-
let execution_engine = ExecutionEngine::new(Rc::new(execution_engine), false);
428+
let context = self.non_global_context.clone();
429+
let execution_engine = ExecutionEngine::new(Rc::new(execution_engine), context, false);
429430

430431
*self.owned_by_ee.borrow_mut() = Some(execution_engine.clone());
431432

@@ -461,7 +462,8 @@ impl Module {
461462
return Err(LLVMString::new(err_string));
462463
}
463464

464-
let execution_engine = ExecutionEngine::new(Rc::new(execution_engine), false);
465+
let context = self.non_global_context.clone();
466+
let execution_engine = ExecutionEngine::new(Rc::new(execution_engine), context, false);
465467

466468
*self.owned_by_ee.borrow_mut() = Some(execution_engine.clone());
467469

@@ -510,7 +512,8 @@ impl Module {
510512
return Err(LLVMString::new(err_string));
511513
}
512514

513-
let execution_engine = ExecutionEngine::new(Rc::new(execution_engine), true);
515+
let context = self.non_global_context.clone();
516+
let execution_engine = ExecutionEngine::new(Rc::new(execution_engine), context, true);
514517

515518
*self.owned_by_ee.borrow_mut() = Some(execution_engine.clone());
516519

tests/all/test_execution_engine.rs

+25
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,28 @@ fn test_add_remove_module() {
203203

204204
// assert!(execution_engine.get_function_value("func").is_ok());
205205
// }
206+
207+
208+
#[test]
209+
fn test_previous_double_free() {
210+
Target::initialize_native(&InitializationConfig::default()).unwrap();
211+
212+
let context = Context::create();
213+
let module = context.create_module("sum");
214+
let ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
215+
216+
drop(context);
217+
drop(module);
218+
}
219+
220+
#[test]
221+
fn test_previous_double_free2() {
222+
Target::initialize_native(&InitializationConfig::default()).unwrap();
223+
224+
let _execution_engine = {
225+
let context = Context::create();
226+
let module = context.create_module("sum");
227+
228+
module.create_jit_execution_engine(OptimizationLevel::None).unwrap()
229+
};
230+
}

0 commit comments

Comments
 (0)