From 3af28f0b7094046a190acc7e823b170694f085b9 Mon Sep 17 00:00:00 2001 From: erer1243 Date: Mon, 4 Mar 2024 16:17:23 -0500 Subject: [PATCH] Fix 32-bit overflows in LLVM composite constants --- compiler/rustc_codegen_llvm/src/common.rs | 17 ++++---- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 21 ++++------ compiler/rustc_codegen_llvm/src/type_.rs | 2 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 42 +++++++++++++++---- 4 files changed, 52 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 8173e41aff4..25cbd90460f 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -95,11 +95,13 @@ impl<'ll> BackendTypes for CodegenCx<'ll, '_> { impl<'ll> CodegenCx<'ll, '_> { pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value { - unsafe { llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint) } + let len = u64::try_from(elts.len()).expect("LLVMConstArray2 elements len overflow"); + unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) } } pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value { - unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) } + let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow"); + unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) } } pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value { @@ -108,8 +110,8 @@ pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value { pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value { unsafe { - assert_eq!(idx as c_uint as u64, idx); - let r = llvm::LLVMGetAggregateElement(v, idx as c_uint).unwrap(); + let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow"); + let r = llvm::LLVMGetAggregateElement(v, idx).unwrap(); debug!("const_get_elt(v={:?}, idx={}, r={:?})", v, idx, r); @@ -329,7 +331,7 @@ pub fn val_ty(v: &Value) -> &Type { pub fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value { unsafe { let ptr = bytes.as_ptr() as *const c_char; - llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True) + llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), True) } } @@ -338,9 +340,8 @@ pub fn struct_in_context<'ll>( elts: &[&'ll Value], packed: bool, ) -> &'ll Value { - unsafe { - llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), elts.len() as c_uint, packed as Bool) - } + let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow"); + unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed as Bool) } } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 58e98037067..d34c289887e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -936,10 +936,16 @@ pub fn LLVMMDNodeInContext2<'a>( pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value; // Operations on composite constants - pub fn LLVMConstStringInContext( + pub fn LLVMConstArray2<'a>( + ElementTy: &'a Type, + ConstantVals: *const &'a Value, + Length: u64, + ) -> &'a Value; + pub fn LLVMArrayType2(ElementType: &Type, ElementCount: u64) -> &Type; + pub fn LLVMConstStringInContext2( C: &Context, Str: *const c_char, - Length: c_uint, + Length: size_t, DontNullTerminate: Bool, ) -> &Value; pub fn LLVMConstStructInContext<'a>( @@ -948,14 +954,6 @@ pub fn LLVMConstStructInContext<'a>( Count: c_uint, Packed: Bool, ) -> &'a Value; - - // FIXME: replace with LLVMConstArray2 when bumped minimal version to llvm-17 - // https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc - pub fn LLVMConstArray<'a>( - ElementTy: &'a Type, - ConstantVals: *const &'a Value, - Length: c_uint, - ) -> &'a Value; pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value; // Constant expressions @@ -1530,9 +1528,6 @@ pub fn LLVMStructSetBody<'a>( /// See llvm::LLVMTypeKind::getTypeID. pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind; - // Operations on array, pointer, and vector types (sequence types) - pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type; - // Operations on all values pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); pub fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 07a4861ed73..af1bbda4d08 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -233,7 +233,7 @@ fn val_ty(&self, v: &'ll Value) -> &'ll Type { } fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type { - unsafe { llvm::LLVMRustArrayType(ty, len) } + unsafe { llvm::LLVMArrayType2(ty, len) } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 3e998d428ee..d76dea6f86c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -10,6 +10,7 @@ #include "llvm/IR/IntrinsicsARM.h" #include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/Mangler.h" +#include "llvm/IR/Value.h" #include "llvm/Remarks/RemarkStreamer.h" #include "llvm/Remarks/RemarkSerializer.h" #include "llvm/Remarks/RemarkFormat.h" @@ -1223,14 +1224,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, } } -// LLVMArrayType function does not support 64-bit ElementCount -// FIXME: replace with LLVMArrayType2 when bumped minimal version to llvm-17 -// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc -extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy, - uint64_t ElementCount) { - return wrap(ArrayType::get(unwrap(ElementTy), ElementCount)); -} - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef) extern "C" void LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef Str) { @@ -2114,3 +2107,36 @@ extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() { extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() { return llvm::compression::zstd::isAvailable(); } + +// Operations on composite constants. +// These are clones of LLVM api functions that will become available in future releases. +// They can be removed once Rust's minimum supported LLVM version supports them. +// See https://github.com/rust-lang/rust/issues/121868 +// See https://llvm.org/doxygen/group__LLVMCCoreValueConstantComposite.html + +// FIXME: Remove when Rust's minimum supported LLVM version reaches 19. +// https://github.com/llvm/llvm-project/commit/e1405e4f71c899420ebf8262d5e9745598419df8 +#if LLVM_VERSION_LT(19, 0) +extern "C" LLVMValueRef LLVMConstStringInContext2(LLVMContextRef C, + const char *Str, + size_t Length, + bool DontNullTerminate) { + return wrap(ConstantDataArray::getString(*unwrap(C), StringRef(Str, Length), !DontNullTerminate)); +} +#endif + +// FIXME: Remove when Rust's minimum supported LLVM version reaches 17. +// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc +#if LLVM_VERSION_LT(17, 0) +extern "C" LLVMValueRef LLVMConstArray2(LLVMTypeRef ElementTy, + LLVMValueRef *ConstantVals, + uint64_t Length) { + ArrayRef V(unwrap(ConstantVals, Length), Length); + return wrap(ConstantArray::get(ArrayType::get(unwrap(ElementTy), Length), V)); +} + +extern "C" LLVMTypeRef LLVMArrayType2(LLVMTypeRef ElementTy, + uint64_t ElementCount) { + return wrap(ArrayType::get(unwrap(ElementTy), ElementCount)); +} +#endif