Skip to content

Commit 41b9624

Browse files
authored
Merge pull request rust-lang#170 from rtfeldman/result-power-of-two
Err for invalid memcpy/memmove alignmen
2 parents 05ba1a5 + cc0c872 commit 41b9624

File tree

2 files changed

+58
-21
lines changed

2 files changed

+58
-21
lines changed

src/builder.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ impl<'ctx> Builder<'ctx> {
351351

352352
/// Build a [memcpy](https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic) instruction.
353353
///
354-
/// Alignment arguments are specified in bytes, and should always be a power of 2.
354+
/// Alignment arguments are specified in bytes, and should always be
355+
/// both a power of 2 and under 2^64.
355356
///
356357
/// The final argument should be a pointer-sized integer.
357358
///
@@ -364,7 +365,15 @@ impl<'ctx> Builder<'ctx> {
364365
src: PointerValue<'ctx>,
365366
src_align_bytes: u32,
366367
size: IntValue<'ctx>,
367-
) -> PointerValue<'ctx> {
368+
) -> Result<PointerValue<'ctx>, &'static str> {
369+
if !is_alignment_ok(src_align_bytes) {
370+
return Err("The src_align_bytes argument to build_memcpy was not a power of 2.");
371+
}
372+
373+
if !is_alignment_ok(dest_align_bytes) {
374+
return Err("The dest_align_bytes argument to build_memcpy was not a power of 2.");
375+
}
376+
368377
let value = unsafe {
369378
LLVMBuildMemCpy(
370379
self.builder,
@@ -376,12 +385,13 @@ impl<'ctx> Builder<'ctx> {
376385
)
377386
};
378387

379-
PointerValue::new(value)
388+
Ok(PointerValue::new(value))
380389
}
381390

382391
/// Build a [memmove](http://llvm.org/docs/LangRef.html#llvm-memmove-intrinsic) instruction.
383392
///
384-
/// Alignment arguments are specified in bytes, and should always be a power of 2.
393+
/// Alignment arguments are specified in bytes, and should always be
394+
/// both a power of 2 and under 2^64.
385395
///
386396
/// The final argument should be a pointer-sized integer.
387397
///
@@ -394,7 +404,15 @@ impl<'ctx> Builder<'ctx> {
394404
src: PointerValue<'ctx>,
395405
src_align_bytes: u32,
396406
size: IntValue<'ctx>,
397-
) -> PointerValue<'ctx> {
407+
) -> Result<PointerValue<'ctx>, &'static str> {
408+
if !is_alignment_ok(src_align_bytes) {
409+
return Err("The src_align_bytes argument to build_memmove was not a power of 2 under 2^64.");
410+
}
411+
412+
if !is_alignment_ok(dest_align_bytes) {
413+
return Err("The dest_align_bytes argument to build_memmove was not a power of 2 under 2^64.");
414+
}
415+
398416
let value = unsafe {
399417
LLVMBuildMemMove(
400418
self.builder,
@@ -406,7 +424,7 @@ impl<'ctx> Builder<'ctx> {
406424
)
407425
};
408426

409-
PointerValue::new(value)
427+
Ok(PointerValue::new(value))
410428
}
411429

412430
// TODOC: Heap allocation
@@ -1706,6 +1724,15 @@ impl<'ctx> Builder<'ctx> {
17061724
}
17071725
}
17081726

1727+
/// Used by build_memcpy and build_memmove
1728+
fn is_alignment_ok(align: u32) -> bool {
1729+
// This replicates the assertions LLVM runs.
1730+
//
1731+
// See https://github.com/TheDan64/inkwell/issues/168
1732+
align > 0 && align.is_power_of_two() && (align as f64).log2() < 64.0
1733+
}
1734+
1735+
17091736
impl Drop for Builder<'_> {
17101737
fn drop(&mut self) {
17111738
unsafe {

tests/all/test_builder.rs

+25-15
Original file line numberDiff line numberDiff line change
@@ -648,27 +648,33 @@ fn test_insert_value() {
648648
assert!(module.verify().is_ok());
649649
}
650650

651+
fn is_alignment_ok(align: u32) -> bool {
652+
// This replicates the assertions LLVM runs.
653+
//
654+
// See https://github.com/TheDan64/inkwell/issues/168
655+
align > 0 && align.is_power_of_two() && (align as f64).log2() < 64.0
656+
}
657+
651658
#[llvm_versions(8.0..=latest)]
652659
#[test]
653660
fn test_alignment_bytes() {
654661
let verify_alignment = |alignment: u32| {
655662
let context = Context::create();
656663
let module = context.create_module("av");
664+
let result = run_memcpy_on(&context, &module, alignment);
657665

658-
run_memcpy_on(&context, &module, alignment);
659-
660-
if alignment == 0 || alignment.is_power_of_two() {
661-
assert!(module.verify().is_ok(), "alignment of {:?} was neither 0 nor a power of 2, but did not verify for memcpy.", alignment);
666+
if is_alignment_ok(alignment) {
667+
assert!(result.is_ok() && module.verify().is_ok(), "alignment of {} was a power of 2 under 2^64, but did not verify for memcpy.", alignment);
662668
} else {
663-
assert!(module.verify().is_err(), "alignment of {:?} was neither 0 nor a power of 2, yet verification passed for memcpy when it should not have.", alignment);
669+
assert!(result.is_err(), "alignment of {} was a power of 2 under 2^64, yet verification passed for memcpy when it should not have.", alignment);
664670
}
665671

666-
run_memmove_on(&context, &module, alignment);
672+
let result = run_memmove_on(&context, &module, alignment);
667673

668-
if alignment == 0 || alignment.is_power_of_two() {
669-
assert!(module.verify().is_ok(), "alignment of {:?} was neither 0 nor a power of 2, but did not verify for memmov.", alignment);
674+
if is_alignment_ok(alignment) {
675+
assert!(result.is_ok() && module.verify().is_ok(), "alignment of {} was a power of 2 under 2^64, but did not verify for memmove.", alignment);
670676
} else {
671-
assert!(module.verify().is_err(), "alignment of {:?} was neither 0 nor a power of 2, yet verification passed for memmov when it should not have.", alignment);
677+
assert!(result.is_err(), "alignment of {} was a power of 2 under 2^64, yet verification passed for memmove when it should not have.", alignment);
672678
}
673679
};
674680

@@ -680,7 +686,7 @@ fn test_alignment_bytes() {
680686
}
681687

682688
#[llvm_versions(8.0..=latest)]
683-
fn run_memcpy_on<'ctx>(context: &'ctx Context, module: &self::inkwell::module::Module<'ctx>, alignment: u32) {
689+
fn run_memcpy_on<'ctx>(context: &'ctx Context, module: &self::inkwell::module::Module<'ctx>, alignment: u32) -> Result<(), &'static str> {
684690
let i32_type = context.i32_type();
685691
let i64_type = context.i64_type();
686692
let array_len = 4;
@@ -710,9 +716,11 @@ fn run_memcpy_on<'ctx>(context: &'ctx Context, module: &self::inkwell::module::M
710716
let index_val = i32_type.const_int(2, false);
711717
let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") };
712718

713-
builder.build_memcpy(dest_ptr, alignment, array_ptr, alignment, size_val);
719+
builder.build_memcpy(dest_ptr, alignment, array_ptr, alignment, size_val)?;
714720

715721
builder.build_return(Some(&array_ptr));
722+
723+
Ok(())
716724
}
717725

718726
#[llvm_versions(8.0..=latest)]
@@ -724,7 +732,7 @@ fn test_memcpy() {
724732
let context = Context::create();
725733
let module = context.create_module("av");
726734

727-
run_memcpy_on(&context, &module, 8);
735+
assert!(run_memcpy_on(&context, &module, 8).is_ok());
728736

729737
// Verify the module
730738
if let Err(errors) = module.verify() {
@@ -742,7 +750,7 @@ fn test_memcpy() {
742750
}
743751

744752
#[llvm_versions(8.0..=latest)]
745-
fn run_memmove_on<'ctx>(context: &'ctx Context, module: &self::inkwell::module::Module<'ctx>, alignment: u32) {
753+
fn run_memmove_on<'ctx>(context: &'ctx Context, module: &self::inkwell::module::Module<'ctx>, alignment: u32) -> Result<(), &'static str> {
746754
let i32_type = context.i32_type();
747755
let i64_type = context.i64_type();
748756
let array_len = 4;
@@ -772,9 +780,11 @@ fn run_memmove_on<'ctx>(context: &'ctx Context, module: &self::inkwell::module::
772780
let index_val = i32_type.const_int(2, false);
773781
let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") };
774782

775-
builder.build_memmove(dest_ptr, alignment, array_ptr, alignment, size_val);
783+
builder.build_memmove(dest_ptr, alignment, array_ptr, alignment, size_val)?;
776784

777785
builder.build_return(Some(&array_ptr));
786+
787+
Ok(())
778788
}
779789

780790
#[llvm_versions(8.0..=latest)]
@@ -786,7 +796,7 @@ fn test_memmove() {
786796
let context = Context::create();
787797
let module = context.create_module("av");
788798

789-
run_memcpy_on(&context, &module, 8);
799+
assert!(run_memcpy_on(&context, &module, 8).is_ok());
790800

791801
// Verify the module
792802
if let Err(errors) = module.verify() {

0 commit comments

Comments
 (0)