Skip to content

Commit 499e6f8

Browse files
authored
Auto merge of #34594 - willcrichton:master, r=nrc
Move LLVM cleanup so modules are accessible during `after_llvm` phase Fix for #34432. Also added a new phase controller `after_compilation_done` that gets called at the very end (i.e. after linking) at the suggestion of @nrc. The added test will segfault if the modules get deallocated too early, so it ensures the LLVM is not prematurely cleaned up. r? @nrc
2 parents 0f4c4f8 + 5b0f334 commit 499e6f8

File tree

4 files changed

+117
-2
lines changed

4 files changed

+117
-2
lines changed

src/librustc_driver/driver.rs

+20
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,15 @@ pub fn compile_input(sess: &Session,
225225
phase5_result);
226226
phase5_result?;
227227

228+
write::cleanup_llvm(&trans);
229+
228230
phase_6_link_output(sess, &trans, &outputs);
229231

232+
controller_entry_point!(compilation_done,
233+
sess,
234+
CompileState::state_when_compilation_done(input, sess, outdir, output),
235+
Ok(()));
236+
230237
Ok(())
231238
}
232239

@@ -274,6 +281,7 @@ pub struct CompileController<'a> {
274281
pub after_hir_lowering: PhaseController<'a>,
275282
pub after_analysis: PhaseController<'a>,
276283
pub after_llvm: PhaseController<'a>,
284+
pub compilation_done: PhaseController<'a>,
277285

278286
pub make_glob_map: MakeGlobMap,
279287
}
@@ -286,6 +294,7 @@ impl<'a> CompileController<'a> {
286294
after_hir_lowering: PhaseController::basic(),
287295
after_analysis: PhaseController::basic(),
288296
after_llvm: PhaseController::basic(),
297+
compilation_done: PhaseController::basic(),
289298
make_glob_map: MakeGlobMap::No,
290299
}
291300
}
@@ -453,6 +462,17 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> {
453462
..CompileState::empty(input, session, out_dir)
454463
}
455464
}
465+
466+
fn state_when_compilation_done(input: &'a Input,
467+
session: &'ast Session,
468+
out_dir: &'a Option<PathBuf>,
469+
out_file: &'a Option<PathBuf>)
470+
-> CompileState<'a, 'b, 'ast, 'tcx> {
471+
CompileState {
472+
out_file: out_file.as_ref().map(|s| &**s),
473+
..CompileState::empty(input, session, out_dir)
474+
}
475+
}
456476
}
457477

458478
pub fn phase_1_parse_input<'a>(sess: &'a Session,

src/librustc_trans/back/write.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -616,11 +616,19 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
616616
}
617617
}
618618

619-
llvm::LLVMDisposeModule(llmod);
620-
llvm::LLVMContextDispose(llcx);
621619
llvm::LLVMRustDisposeTargetMachine(tm);
622620
}
623621

622+
623+
pub fn cleanup_llvm(trans: &CrateTranslation) {
624+
for module in trans.modules.iter() {
625+
unsafe {
626+
llvm::LLVMDisposeModule(module.llmod);
627+
llvm::LLVMContextDispose(module.llcx);
628+
}
629+
}
630+
}
631+
624632
pub fn run_passes(sess: &Session,
625633
trans: &CrateTranslation,
626634
output_types: &HashMap<OutputType, Option<PathBuf>>,

src/test/run-make/llvm-phase/Makefile

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) test.rs
5+
$(call RUN,test $(RUSTC))

src/test/run-make/llvm-phase/test.rs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(plugin, rustc_private, box_syntax)]
12+
13+
extern crate rustc;
14+
extern crate rustc_driver;
15+
extern crate rustc_llvm;
16+
#[macro_use] extern crate syntax;
17+
extern crate getopts;
18+
19+
use rustc_driver::{CompilerCalls, Compilation};
20+
use rustc_driver::driver::CompileController;
21+
use rustc::session::Session;
22+
use syntax::codemap::FileLoader;
23+
use std::io;
24+
use std::path::{PathBuf, Path};
25+
26+
struct JitLoader;
27+
28+
impl FileLoader for JitLoader {
29+
fn file_exists(&self, _: &Path) -> bool { true }
30+
fn abs_path(&self, _: &Path) -> Option<PathBuf> { None }
31+
fn read_file(&self, _: &Path) -> io::Result<String> {
32+
Ok(r#"
33+
#[no_mangle]
34+
pub fn test_add(a: i32, b: i32) -> i32 { a + b }
35+
"#.to_string())
36+
}
37+
}
38+
39+
#[derive(Copy, Clone)]
40+
struct JitCalls;
41+
42+
impl<'a> CompilerCalls<'a> for JitCalls {
43+
fn build_controller(&mut self,
44+
_: &Session,
45+
_: &getopts::Matches)
46+
-> CompileController<'a> {
47+
let mut cc = CompileController::basic();
48+
cc.after_llvm.stop = Compilation::Stop;
49+
cc.after_llvm.run_callback_on_error = true;
50+
cc.after_llvm.callback = Box::new(|state| {
51+
state.session.abort_if_errors();
52+
let trans = state.trans.unwrap();
53+
assert_eq!(trans.modules.len(), 1);
54+
let rs_llmod = trans.modules[0].llmod;
55+
unsafe { rustc_llvm::LLVMDumpModule(rs_llmod) };
56+
});
57+
cc
58+
}
59+
}
60+
61+
fn main() {
62+
use rustc_driver;
63+
64+
let mut path = match std::env::args().nth(2) {
65+
Some(path) => PathBuf::from(&path),
66+
None => panic!("missing rustc path")
67+
};
68+
69+
// Remove two segments from rustc path to get sysroot.
70+
path.pop();
71+
path.pop();
72+
73+
let args: Vec<String> =
74+
format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap())
75+
.split(' ').map(|s| s.to_string()).collect();
76+
77+
let (result, _) = rustc_driver::run_compiler_with_file_loader(
78+
&args, &mut JitCalls, box JitLoader);
79+
if let Err(n) = result {
80+
panic!("Error {}", n);
81+
}
82+
}

0 commit comments

Comments
 (0)