Auto merge of #38048 - rkruppe:llvm-stringref-fixes, r=alexcrichton

[LLVM 4.0] Don't assume llvm::StringRef is null terminated

StringRefs have a length and their contents are not usually null-terminated. The solution is to either copy the string data (in `rustc_llvm::diagnostic`) or take the size into account (in LLVMRustPrintPasses).

I couldn't trigger a bug caused by this (apparently all the strings returned in practice are actually null-terminated) but this is more correct and more future-proof.

cc #37609
This commit is contained in:
bors 2016-12-01 15:21:11 +00:00
commit 908dba0c94
5 changed files with 26 additions and 28 deletions

View File

@ -13,7 +13,7 @@
pub use self::OptimizationDiagnosticKind::*; pub use self::OptimizationDiagnosticKind::*;
pub use self::Diagnostic::*; pub use self::Diagnostic::*;
use libc::{c_char, c_uint}; use libc::c_uint;
use std::ptr; use std::ptr;
use {DiagnosticInfoRef, TwineRef, ValueRef}; use {DiagnosticInfoRef, TwineRef, ValueRef};
@ -45,7 +45,7 @@ impl OptimizationDiagnosticKind {
pub struct OptimizationDiagnostic { pub struct OptimizationDiagnostic {
pub kind: OptimizationDiagnosticKind, pub kind: OptimizationDiagnosticKind,
pub pass_name: *const c_char, pub pass_name: String,
pub function: ValueRef, pub function: ValueRef,
pub debug_loc: DebugLocRef, pub debug_loc: DebugLocRef,
pub message: String, pub message: String,
@ -55,21 +55,23 @@ impl OptimizationDiagnostic {
unsafe fn unpack(kind: OptimizationDiagnosticKind, unsafe fn unpack(kind: OptimizationDiagnosticKind,
di: DiagnosticInfoRef) di: DiagnosticInfoRef)
-> OptimizationDiagnostic { -> OptimizationDiagnostic {
let mut pass_name = ptr::null();
let mut function = ptr::null_mut(); let mut function = ptr::null_mut();
let mut debug_loc = ptr::null_mut(); let mut debug_loc = ptr::null_mut();
let message = super::build_string(|message| let mut message = None;
super::LLVMRustUnpackOptimizationDiagnostic(di, let pass_name = super::build_string(|pass_name|
&mut pass_name, message = super::build_string(|message|
&mut function, super::LLVMRustUnpackOptimizationDiagnostic(di,
&mut debug_loc, pass_name,
message) &mut function,
&mut debug_loc,
message)
)
); );
OptimizationDiagnostic { OptimizationDiagnostic {
kind: kind, kind: kind,
pass_name: pass_name, pass_name: pass_name.expect("got a non-UTF8 pass name from LLVM"),
function: function, function: function,
debug_loc: debug_loc, debug_loc: debug_loc,
message: message.expect("got a non-UTF8 OptimizationDiagnostic message from LLVM") message: message.expect("got a non-UTF8 OptimizationDiagnostic message from LLVM")

View File

@ -1820,7 +1820,7 @@ extern "C" {
DiagnosticContext: *mut c_void); DiagnosticContext: *mut c_void);
pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef, pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef,
pass_name_out: *mut *const c_char, pass_name_out: RustStringRef,
function_out: *mut ValueRef, function_out: *mut ValueRef,
debugloc_out: *mut DebugLocRef, debugloc_out: *mut DebugLocRef,
message_out: RustStringRef); message_out: RustStringRef);

View File

@ -26,7 +26,7 @@ use errors::emitter::Emitter;
use syntax_pos::MultiSpan; use syntax_pos::MultiSpan;
use context::{is_pie_binary, get_reloc_model}; use context::{is_pie_binary, get_reloc_model};
use std::ffi::{CStr, CString}; use std::ffi::CString;
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str; use std::str;
@ -403,19 +403,16 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
} }
llvm::diagnostic::Optimization(opt) => { llvm::diagnostic::Optimization(opt) => {
let pass_name = str::from_utf8(CStr::from_ptr(opt.pass_name).to_bytes())
.ok()
.expect("got a non-UTF8 pass name from LLVM");
let enabled = match cgcx.remark { let enabled = match cgcx.remark {
AllPasses => true, AllPasses => true,
SomePasses(ref v) => v.iter().any(|s| *s == pass_name), SomePasses(ref v) => v.iter().any(|s| *s == opt.pass_name),
}; };
if enabled { if enabled {
let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc); let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc);
cgcx.handler.note_without_error(&format!("optimization {} for {} at {}: {}", cgcx.handler.note_without_error(&format!("optimization {} for {} at {}: {}",
opt.kind.describe(), opt.kind.describe(),
pass_name, opt.pass_name,
if loc.is_empty() { "[unknown]" } else { &*loc }, if loc.is_empty() { "[unknown]" } else { &*loc },
opt.message)); opt.message));
} }

View File

@ -530,9 +530,11 @@ LLVMRustPrintPasses() {
struct MyListener : PassRegistrationListener { struct MyListener : PassRegistrationListener {
void passEnumerate(const PassInfo *info) { void passEnumerate(const PassInfo *info) {
#if LLVM_VERSION_GE(4, 0) #if LLVM_VERSION_GE(4, 0)
if (!info->getPassArgument().empty()) { StringRef PassArg = info->getPassArgument();
printf("%15s - %s\n", info->getPassArgument().data(), StringRef PassName = info->getPassName();
info->getPassName().data()); if (!PassArg.empty()) {
printf("%15.*s - %.*s\n", PassArg.size(), PassArg.data(),
PassName.size(), PassName.data());
} }
#else #else
if (info->getPassArgument() && *info->getPassArgument()) { if (info->getPassArgument() && *info->getPassArgument()) {

View File

@ -872,7 +872,7 @@ LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef str) {
extern "C" void extern "C" void
LLVMRustUnpackOptimizationDiagnostic( LLVMRustUnpackOptimizationDiagnostic(
LLVMDiagnosticInfoRef di, LLVMDiagnosticInfoRef di,
const char **pass_name_out, RustStringRef pass_name_out,
LLVMValueRef *function_out, LLVMValueRef *function_out,
LLVMDebugLocRef *debugloc_out, LLVMDebugLocRef *debugloc_out,
RustStringRef message_out) RustStringRef message_out)
@ -881,15 +881,12 @@ LLVMRustUnpackOptimizationDiagnostic(
llvm::DiagnosticInfoOptimizationBase *opt llvm::DiagnosticInfoOptimizationBase *opt
= static_cast<llvm::DiagnosticInfoOptimizationBase*>(unwrap(di)); = static_cast<llvm::DiagnosticInfoOptimizationBase*>(unwrap(di));
#if LLVM_VERSION_GE(4, 0) raw_rust_string_ostream pass_name_os(pass_name_out);
*pass_name_out = opt->getPassName().data(); pass_name_os << opt->getPassName();
#else
*pass_name_out = opt->getPassName();
#endif
*function_out = wrap(&opt->getFunction()); *function_out = wrap(&opt->getFunction());
*debugloc_out = wrap(&opt->getDebugLoc()); *debugloc_out = wrap(&opt->getDebugLoc());
raw_rust_string_ostream os(message_out); raw_rust_string_ostream message_os(message_out);
os << opt->getMsg(); message_os << opt->getMsg();
} }
extern "C" void extern "C" void