]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Stop using LLVMGetSectionName
authorAlex Crichton <alex@alexcrichton.com>
Thu, 3 Apr 2014 17:45:36 +0000 (10:45 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 3 Apr 2014 17:49:35 +0000 (10:49 -0700)
The recent pull request to remove libc from libstd has hit a wall in compiling
on windows, and I've been trying to investigate on the try bots as to why (it
compiles locally just fine). To the best of my knowledge, the LLVM section
iterator is behaving badly when iterating over the sections of the libc DLL.

Upon investigating the LLVMGetSectionName function in LLVM, I discovered that
this function doesn't always return a null-terminated string. It returns the
data pointer of a StringRef instance (LLVM's equivalent of &str essentially),
but it has no method of returning the length of the name of the section.

This commit modifies the section iteration when loading libraries to invoke a
custom LLVMRustGetSectionName which will correctly return both the length and
the data pointer.

I have not yet verified that this will fix landing liblibc, as it will require a
snapshot before doing a full test. Regardless, this is a worrisome situation
regarding the LLVM API, and should likely be fixed anyway.

src/librustc/lib/llvm.rs
src/librustc/metadata/loader.rs
src/rustllvm/RustWrapper.cpp

index a733d2672e820292b1fecb05b1a6ea0a64a1e518..9cfe064ad986f9ee63225cf1fd7e73e2f6f0b1bc 100644 (file)
@@ -1438,8 +1438,6 @@ pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef,
                                           -> Bool;
         /** Moves the section iterator to point to the next section. */
         pub fn LLVMMoveToNextSection(SI: SectionIteratorRef);
-        /** Returns the current section name. */
-        pub fn LLVMGetSectionName(SI: SectionIteratorRef) -> *c_char;
         /** Returns the current section size. */
         pub fn LLVMGetSectionSize(SI: SectionIteratorRef) -> c_ulonglong;
         /** Returns the current section contents as a string buffer. */
@@ -1784,6 +1782,9 @@ pub fn LLVMRustArchiveReadSection(AR: ArchiveRef, name: *c_char,
 
         pub fn LLVMRustSetDLLExportStorageClass(V: ValueRef);
         pub fn LLVMVersionMinor() -> c_int;
+
+        pub fn LLVMRustGetSectionName(SI: SectionIteratorRef,
+                                      data: *mut *c_char) -> c_int;
     }
 }
 
index 8a3d6567c77a1b52c66475890265d87cd42ef94f..4dd892fd703452dc87786feaf3177b00fddc87e4 100644 (file)
 use std::cmp;
 use std::io;
 use std::os::consts::{macos, freebsd, linux, android, win32};
+use std::ptr;
 use std::rc::Rc;
-use std::str;
 use std::slice;
+use std::str;
 
 use collections::{HashMap, HashSet};
 use flate;
@@ -439,8 +440,9 @@ fn get_metadata_section_imp(os: Os, filename: &Path) -> Result<MetadataBlob, ~st
         };
         let si = mk_section_iter(of.llof);
         while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
-            let name_buf = llvm::LLVMGetSectionName(si.llsi);
-            let name = str::raw::from_c_str(name_buf);
+            let mut name_buf = ptr::null();
+            let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
+            let name = str::raw::from_buf_len(name_buf as *u8, name_len as uint);
             debug!("get_metadata_section: name {}", name);
             if read_meta_section_name(os) == name {
                 let cbuf = llvm::LLVMGetSectionContents(si.llsi);
index 4755c7873fcb2114f66d765cc0f584f6908a1297..5a00a8034e6bc6dda6eb4616c6a0c8082de70a96 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "rustllvm.h"
 #include "llvm/Object/Archive.h"
+#include "llvm/Object/ObjectFile.h"
 
 //===----------------------------------------------------------------------===
 //
@@ -679,3 +680,27 @@ extern "C" int
 LLVMVersionMinor() {
     return LLVM_VERSION_MINOR;
 }
+
+// Note that the two following functions look quite similar to the
+// LLVMGetSectionName function. Sadly, it appears that this function only
+// returns a char* pointer, which isn't guaranteed to be null-terminated. The
+// function provided by LLVM doesn't return the length, so we've created our own
+// function which returns the length as well as the data pointer.
+//
+// For an example of this not returning a null terminated string, see
+// lib/Object/COFFObjectFile.cpp in the getSectionName function. One of the
+// branches explicitly creates a StringRef without a null terminator, and then
+// that's returned.
+
+inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
+    return reinterpret_cast<section_iterator*>(SI);
+}
+
+extern "C" int
+LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) {
+    StringRef ret;
+    if (error_code ec = (*unwrap(SI))->getName(ret))
+      report_fatal_error(ec.message());
+    *ptr = ret.data();
+    return ret.size();
+}