Skip to content

Commit 60f4b7a

Browse files
authored
Rollup merge of rust-lang#122000 - erer1243:issue-121868, r=nikic
Fix 32-bit overflows in LLVM composite constants Inspired by rust-lang#121868. Fixes unsoundness created when constructing constant arrays, strings, and structs with 2^32 or more elements on x86_64. This introduces copies of a few LLVM functions that have their signatures updated to use size_t in place of unsigned int. Alternatively we could just add overflow checks and just disallow huge composite constants. That introduces less code, but maybe a huge static block of memory is useful in embedded/no-os situations?
2 parents b4cbc88 + 3af28f0 commit 60f4b7a

File tree

4 files changed

+52
-30
lines changed

4 files changed

+52
-30
lines changed

compiler/rustc_codegen_llvm/src/common.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,13 @@ impl<'ll> BackendTypes for CodegenCx<'ll, '_> {
9595

9696
impl<'ll> CodegenCx<'ll, '_> {
9797
pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
98-
unsafe { llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint) }
98+
let len = u64::try_from(elts.len()).expect("LLVMConstArray2 elements len overflow");
99+
unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) }
99100
}
100101

101102
pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
102-
unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) }
103+
let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow");
104+
unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) }
103105
}
104106

105107
pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
@@ -108,8 +110,8 @@ impl<'ll> CodegenCx<'ll, '_> {
108110

109111
pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
110112
unsafe {
111-
assert_eq!(idx as c_uint as u64, idx);
112-
let r = llvm::LLVMGetAggregateElement(v, idx as c_uint).unwrap();
113+
let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow");
114+
let r = llvm::LLVMGetAggregateElement(v, idx).unwrap();
113115

114116
debug!("const_get_elt(v={:?}, idx={}, r={:?})", v, idx, r);
115117

@@ -329,7 +331,7 @@ pub fn val_ty(v: &Value) -> &Type {
329331
pub fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
330332
unsafe {
331333
let ptr = bytes.as_ptr() as *const c_char;
332-
llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True)
334+
llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), True)
333335
}
334336
}
335337

@@ -338,9 +340,8 @@ pub fn struct_in_context<'ll>(
338340
elts: &[&'ll Value],
339341
packed: bool,
340342
) -> &'ll Value {
341-
unsafe {
342-
llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), elts.len() as c_uint, packed as Bool)
343-
}
343+
let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow");
344+
unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed as Bool) }
344345
}
345346

346347
#[inline]

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -936,10 +936,16 @@ extern "C" {
936936
pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value;
937937

938938
// Operations on composite constants
939-
pub fn LLVMConstStringInContext(
939+
pub fn LLVMConstArray2<'a>(
940+
ElementTy: &'a Type,
941+
ConstantVals: *const &'a Value,
942+
Length: u64,
943+
) -> &'a Value;
944+
pub fn LLVMArrayType2(ElementType: &Type, ElementCount: u64) -> &Type;
945+
pub fn LLVMConstStringInContext2(
940946
C: &Context,
941947
Str: *const c_char,
942-
Length: c_uint,
948+
Length: size_t,
943949
DontNullTerminate: Bool,
944950
) -> &Value;
945951
pub fn LLVMConstStructInContext<'a>(
@@ -948,14 +954,6 @@ extern "C" {
948954
Count: c_uint,
949955
Packed: Bool,
950956
) -> &'a Value;
951-
952-
// FIXME: replace with LLVMConstArray2 when bumped minimal version to llvm-17
953-
// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc
954-
pub fn LLVMConstArray<'a>(
955-
ElementTy: &'a Type,
956-
ConstantVals: *const &'a Value,
957-
Length: c_uint,
958-
) -> &'a Value;
959957
pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
960958

961959
// Constant expressions
@@ -1530,9 +1528,6 @@ extern "C" {
15301528
/// See llvm::LLVMTypeKind::getTypeID.
15311529
pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind;
15321530

1533-
// Operations on array, pointer, and vector types (sequence types)
1534-
pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type;
1535-
15361531
// Operations on all values
15371532
pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
15381533
pub fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool;

compiler/rustc_codegen_llvm/src/type_.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
233233
}
234234

235235
fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
236-
unsafe { llvm::LLVMRustArrayType(ty, len) }
236+
unsafe { llvm::LLVMArrayType2(ty, len) }
237237
}
238238
}
239239

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+34-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "llvm/IR/IntrinsicsARM.h"
1111
#include "llvm/IR/LLVMRemarkStreamer.h"
1212
#include "llvm/IR/Mangler.h"
13+
#include "llvm/IR/Value.h"
1314
#include "llvm/Remarks/RemarkStreamer.h"
1415
#include "llvm/Remarks/RemarkSerializer.h"
1516
#include "llvm/Remarks/RemarkFormat.h"
@@ -1223,14 +1224,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V,
12231224
}
12241225
}
12251226

1226-
// LLVMArrayType function does not support 64-bit ElementCount
1227-
// FIXME: replace with LLVMArrayType2 when bumped minimal version to llvm-17
1228-
// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc
1229-
extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy,
1230-
uint64_t ElementCount) {
1231-
return wrap(ArrayType::get(unwrap(ElementTy), ElementCount));
1232-
}
1233-
12341227
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef)
12351228

12361229
extern "C" void LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef Str) {
@@ -2114,3 +2107,36 @@ extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() {
21142107
extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
21152108
return llvm::compression::zstd::isAvailable();
21162109
}
2110+
2111+
// Operations on composite constants.
2112+
// These are clones of LLVM api functions that will become available in future releases.
2113+
// They can be removed once Rust's minimum supported LLVM version supports them.
2114+
// See https://github.com/rust-lang/rust/issues/121868
2115+
// See https://llvm.org/doxygen/group__LLVMCCoreValueConstantComposite.html
2116+
2117+
// FIXME: Remove when Rust's minimum supported LLVM version reaches 19.
2118+
// https://github.com/llvm/llvm-project/commit/e1405e4f71c899420ebf8262d5e9745598419df8
2119+
#if LLVM_VERSION_LT(19, 0)
2120+
extern "C" LLVMValueRef LLVMConstStringInContext2(LLVMContextRef C,
2121+
const char *Str,
2122+
size_t Length,
2123+
bool DontNullTerminate) {
2124+
return wrap(ConstantDataArray::getString(*unwrap(C), StringRef(Str, Length), !DontNullTerminate));
2125+
}
2126+
#endif
2127+
2128+
// FIXME: Remove when Rust's minimum supported LLVM version reaches 17.
2129+
// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc
2130+
#if LLVM_VERSION_LT(17, 0)
2131+
extern "C" LLVMValueRef LLVMConstArray2(LLVMTypeRef ElementTy,
2132+
LLVMValueRef *ConstantVals,
2133+
uint64_t Length) {
2134+
ArrayRef<Constant *> V(unwrap<Constant>(ConstantVals, Length), Length);
2135+
return wrap(ConstantArray::get(ArrayType::get(unwrap(ElementTy), Length), V));
2136+
}
2137+
2138+
extern "C" LLVMTypeRef LLVMArrayType2(LLVMTypeRef ElementTy,
2139+
uint64_t ElementCount) {
2140+
return wrap(ArrayType::get(unwrap(ElementTy), ElementCount));
2141+
}
2142+
#endif

0 commit comments

Comments
 (0)