Skip to content

[breaking change] Fix pointer validation in stdsimd-verify #746

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion crates/core_arch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
rustc_attrs,
stdsimd,
staged_api,
align_offset,
maybe_uninit,
doc_cfg,
mmx_target_feature,
Expand Down
4 changes: 2 additions & 2 deletions crates/core_arch/src/x86/avx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1634,7 +1634,7 @@ pub unsafe fn _mm256_load_pd(mem_addr: *const f64) -> __m256d {
#[cfg_attr(test, assert_instr(vmovaps))] // FIXME vmovapd expected
#[stable(feature = "simd_x86", since = "1.27.0")]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn _mm256_store_pd(mem_addr: *const f64, a: __m256d) {
pub unsafe fn _mm256_store_pd(mem_addr: *mut f64, a: __m256d) {
*(mem_addr as *mut __m256d) = a;
}

Expand Down Expand Up @@ -1664,7 +1664,7 @@ pub unsafe fn _mm256_load_ps(mem_addr: *const f32) -> __m256 {
#[cfg_attr(test, assert_instr(vmovaps))]
#[stable(feature = "simd_x86", since = "1.27.0")]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn _mm256_store_ps(mem_addr: *const f32, a: __m256) {
pub unsafe fn _mm256_store_ps(mem_addr: *mut f32, a: __m256) {
*(mem_addr as *mut __m256) = a;
}

Expand Down
8 changes: 4 additions & 4 deletions crates/core_arch/src/x86/sse2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub unsafe fn _mm_pause() {
#[target_feature(enable = "sse2")]
#[cfg_attr(test, assert_instr(clflush))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_clflush(p: *mut u8) {
pub unsafe fn _mm_clflush(p: *const u8) {
clflush(p)
}

Expand Down Expand Up @@ -3014,7 +3014,7 @@ extern "C" {
#[link_name = "llvm.x86.sse2.pause"]
fn pause();
#[link_name = "llvm.x86.sse2.clflush"]
fn clflush(p: *mut u8);
fn clflush(p: *const u8);
#[link_name = "llvm.x86.sse2.lfence"]
fn lfence();
#[link_name = "llvm.x86.sse2.mfence"]
Expand Down Expand Up @@ -3202,8 +3202,8 @@ mod tests {

#[simd_test(enable = "sse2")]
unsafe fn test_mm_clflush() {
let x = 0;
_mm_clflush(&x as *const _ as *mut u8);
let x = 0_u8;
_mm_clflush(&x as *const _);
}

#[simd_test(enable = "sse2")]
Expand Down
24 changes: 20 additions & 4 deletions crates/stdsimd-verify/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,27 @@ fn to_type(t: &syn::Type) -> proc_macro2::TokenStream {

s => panic!("unspported type: \"{}\"", s),
},
syn::Type::Ptr(syn::TypePtr { ref elem, .. })
| syn::Type::Reference(syn::TypeReference { ref elem, .. }) => {
let tokens = to_type(&elem);
quote! { &Type::Ptr(#tokens) }
syn::Type::Ptr(syn::TypePtr {
ref elem,
ref mutability,
..
})
| syn::Type::Reference(syn::TypeReference {
ref elem,
ref mutability,
..
}) => {
// Both pointers and references can have a mut token (*mut and &mut)
if mutability.is_some() {
let tokens = to_type(&elem);
quote! { &Type::MutPtr(#tokens) }
} else {
// If they don't (*const or &) then they are "const"
let tokens = to_type(&elem);
quote! { &Type::ConstPtr(#tokens) }
}
}

syn::Type::Slice(_) => panic!("unsupported slice"),
syn::Type::Array(_) => panic!("unsupported array"),
syn::Type::Tuple(_) => quote! { &TUPLE },
Expand Down
7 changes: 3 additions & 4 deletions crates/stdsimd-verify/tests/mips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ enum Type {
PrimPoly(u8),
MutPtr(&'static Type),
ConstPtr(&'static Type),
Ptr(&'static Type),
Tuple,
I(u8, u8, u8),
U(u8, u8, u8),
Expand Down Expand Up @@ -91,7 +90,7 @@ enum MsaTy {
i64,
u64,
Void,
VoidPtr,
MutVoidPtr,
}

impl<'a> From<&'a str> for MsaTy {
Expand Down Expand Up @@ -125,7 +124,7 @@ impl<'a> From<&'a str> for MsaTy {
"i64" => MsaTy::i64,
"u64" => MsaTy::u64,
"void" => MsaTy::Void,
"void *" => MsaTy::VoidPtr,
"void *" => MsaTy::MutVoidPtr,
v => panic!("unknown ty: \"{}\"", v),
}
}
Expand Down Expand Up @@ -273,7 +272,7 @@ fn matches(rust: &Function, mips: &MsaIntrinsic) -> Result<(), String> {
MsaTy::i64 if **rust_arg == I64 => (),
MsaTy::u32 if **rust_arg == U32 => (),
MsaTy::u64 if **rust_arg == U64 => (),
MsaTy::VoidPtr if **rust_arg == Type::Ptr(&U8) => (),
MsaTy::MutVoidPtr if **rust_arg == Type::MutPtr(&U8) => (),
m => bail!(
"mismatched argument \"{}\"= \"{:?}\" != \"{:?}\"",
i,
Expand Down
118 changes: 79 additions & 39 deletions crates/stdsimd-verify/tests/x86-intel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ enum Type {
PrimFloat(u8),
PrimSigned(u8),
PrimUnsigned(u8),
Ptr(&'static Type),
MutPtr(&'static Type),
ConstPtr(&'static Type),
M64,
M128,
M128D,
Expand Down Expand Up @@ -409,8 +410,17 @@ fn matches(rust: &Function, intel: &Intrinsic) -> Result<(), String> {
}

fn equate(t: &Type, intel: &str, intrinsic: &str, is_const: bool) -> Result<(), String> {
let intel = intel.replace(" *", "*");
let intel = intel.replace(" const*", "*");
// Make pointer adjacent to the type: float * foo => float* foo
let mut intel = intel.replace(" *", "*");
// Make mutability modifier adjacent to the pointer:
// float const * foo => float const* foo
intel = intel.replace("const *", "const*");
// Normalize mutability modifier to after the type:
// const float* foo => float const*
if intel.starts_with("const") && intel.ends_with("*") {
intel = intel.replace("const ", "");
intel = intel.replace("*", " const*");
}
let require_const = || {
if is_const {
return Ok(());
Expand All @@ -434,54 +444,84 @@ fn equate(t: &Type, intel: &str, intrinsic: &str, is_const: bool) -> Result<(),
(&Type::PrimUnsigned(32), "const unsigned int") => {}
(&Type::PrimUnsigned(64), "unsigned __int64") => {}
(&Type::PrimUnsigned(8), "unsigned char") => {}

(&Type::Ptr(&Type::PrimFloat(32)), "float*") => {}
(&Type::Ptr(&Type::PrimFloat(64)), "double*") => {}
(&Type::Ptr(&Type::PrimSigned(32)), "int*") => {}
(&Type::Ptr(&Type::PrimSigned(32)), "__int32*") => {}
(&Type::Ptr(&Type::PrimSigned(64)), "__int64*") => {}
(&Type::Ptr(&Type::PrimSigned(8)), "char*") => {}
(&Type::Ptr(&Type::PrimUnsigned(16)), "unsigned short*") => {}
(&Type::Ptr(&Type::PrimUnsigned(32)), "unsigned int*") => {}
(&Type::Ptr(&Type::PrimUnsigned(64)), "unsigned __int64*") => {}
(&Type::Ptr(&Type::PrimUnsigned(8)), "const void*") => {}
(&Type::Ptr(&Type::PrimUnsigned(8)), "void*") => {}

(&Type::M64, "__m64") | (&Type::Ptr(&Type::M64), "__m64*") => {}

(&Type::M128I, "__m128i")
| (&Type::Ptr(&Type::M128I), "__m128i*")
| (&Type::M128D, "__m128d")
| (&Type::Ptr(&Type::M128D), "__m128d*")
| (&Type::M128, "__m128")
| (&Type::Ptr(&Type::M128), "__m128*") => {}

(&Type::M256I, "__m256i")
| (&Type::Ptr(&Type::M256I), "__m256i*")
| (&Type::M256D, "__m256d")
| (&Type::Ptr(&Type::M256D), "__m256d*")
| (&Type::M256, "__m256")
| (&Type::Ptr(&Type::M256), "__m256*") => {}

(&Type::M512I, "__m512i")
| (&Type::Ptr(&Type::M512I), "__m512i*")
| (&Type::M512D, "__m512d")
| (&Type::Ptr(&Type::M512D), "__m512d*")
| (&Type::M512, "__m512")
| (&Type::Ptr(&Type::M512), "__m512*") => {}
(&Type::M64, "__m64") => {}
(&Type::M128, "__m128") => {}
(&Type::M128I, "__m128i") => {}
(&Type::M128D, "__m128d") => {}
(&Type::M256, "__m256") => {}
(&Type::M256I, "__m256i") => {}
(&Type::M256D, "__m256d") => {}
(&Type::M512, "__m512") => {}
(&Type::M512I, "__m512i") => {}
(&Type::M512D, "__m512d") => {}

(&Type::MutPtr(&Type::PrimFloat(32)), "float*") => {}
(&Type::MutPtr(&Type::PrimFloat(64)), "double*") => {}
(&Type::MutPtr(&Type::PrimSigned(32)), "int*") => {}
(&Type::MutPtr(&Type::PrimSigned(32)), "__int32*") => {}
(&Type::MutPtr(&Type::PrimSigned(64)), "__int64*") => {}
(&Type::MutPtr(&Type::PrimSigned(8)), "char*") => {}
(&Type::MutPtr(&Type::PrimUnsigned(16)), "unsigned short*") => {}
(&Type::MutPtr(&Type::PrimUnsigned(32)), "unsigned int*") => {}
(&Type::MutPtr(&Type::PrimUnsigned(64)), "unsigned __int64*") => {}
(&Type::MutPtr(&Type::PrimUnsigned(8)), "void*") => {}
(&Type::MutPtr(&Type::M64), "__m64*") => {}
(&Type::MutPtr(&Type::M128), "__m128*") => {}
(&Type::MutPtr(&Type::M128I), "__m128i*") => {}
(&Type::MutPtr(&Type::M128D), "__m128d*") => {}
(&Type::MutPtr(&Type::M256), "__m256*") => {}
(&Type::MutPtr(&Type::M256I), "__m256i*") => {}
(&Type::MutPtr(&Type::M256D), "__m256d*") => {}
(&Type::MutPtr(&Type::M512), "__m512*") => {}
(&Type::MutPtr(&Type::M512I), "__m512i*") => {}
(&Type::MutPtr(&Type::M512D), "__m512d*") => {}

(&Type::ConstPtr(&Type::PrimFloat(32)), "float const*") => {}
(&Type::ConstPtr(&Type::PrimFloat(64)), "double const*") => {}
(&Type::ConstPtr(&Type::PrimSigned(32)), "int const*") => {}
(&Type::ConstPtr(&Type::PrimSigned(32)), "__int32 const*") => {}
(&Type::ConstPtr(&Type::PrimSigned(64)), "__int64 const*") => {}
(&Type::ConstPtr(&Type::PrimSigned(8)), "char const*") => {}
(&Type::ConstPtr(&Type::PrimUnsigned(16)), "unsigned short const*") => {}
(&Type::ConstPtr(&Type::PrimUnsigned(32)), "unsigned int const*") => {}
(&Type::ConstPtr(&Type::PrimUnsigned(64)), "unsigned __int64 const*") => {}
(&Type::ConstPtr(&Type::PrimUnsigned(8)), "void const*") => {}
(&Type::ConstPtr(&Type::M64), "__m64 const*") => {}
(&Type::ConstPtr(&Type::M128), "__m128 const*") => {}
(&Type::ConstPtr(&Type::M128I), "__m128i const*") => {}
(&Type::ConstPtr(&Type::M128D), "__m128d const*") => {}
(&Type::ConstPtr(&Type::M256), "__m256 const*") => {}
(&Type::ConstPtr(&Type::M256I), "__m256i const*") => {}
(&Type::ConstPtr(&Type::M256D), "__m256d const*") => {}
(&Type::ConstPtr(&Type::M512), "__m512 const*") => {}
(&Type::ConstPtr(&Type::M512I), "__m512i const*") => {}
(&Type::ConstPtr(&Type::M512D), "__m512d const*") => {}

(&Type::MMASK16, "__mmask16") => {}

// This is a macro (?) in C which seems to mutate its arguments, but
// that means that we're taking pointers to arguments in rust
// as we're not exposing it as a macro.
(&Type::Ptr(&Type::M128), "__m128") if intrinsic == "_MM_TRANSPOSE4_PS" => {}
(&Type::MutPtr(&Type::M128), "__m128") if intrinsic == "_MM_TRANSPOSE4_PS" => {}

// The _rdtsc intrinsic uses a __int64 return type, but this is a bug in
// the intrinsics guide: https://github.com/rust-lang-nursery/stdsimd/issues/559
// We have manually fixed the bug by changing the return type to `u64`.
(&Type::PrimUnsigned(64), "__int64") if intrinsic == "_rdtsc" => {}

// The _bittest and _bittest64 intrinsics takes a mutable pointer in the
// intrinsics guide even though it never writes through the pointer:
(&Type::ConstPtr(&Type::PrimSigned(32)), "__int32*") if intrinsic == "_bittest" => {}
(&Type::ConstPtr(&Type::PrimSigned(64)), "__int64*") if intrinsic == "_bittest64" => {}
// The _xrstor, _fxrstor, _xrstor64, _fxrstor64 intrinsics take a
// mutable pointer in the intrinsics guide even though they never write
// through the pointer:
(&Type::ConstPtr(&Type::PrimUnsigned(8)), "void*")
if intrinsic == "_xrstor"
|| intrinsic == "_xrstor64"
|| intrinsic == "_fxrstor"
|| intrinsic == "_fxrstor64" => {}

_ => bail!(
"failed to equate: `{}` and {:?} for {}",
intel,
Expand Down