Skip to content
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

Remove most unsafe code #162

Merged
merged 2 commits into from
Oct 20, 2023
Merged

Remove most unsafe code #162

merged 2 commits into from
Oct 20, 2023

Conversation

joshlf
Copy link
Contributor

@joshlf joshlf commented Aug 25, 2023

The only remaining unsafe code is used to call SIMD intrinsics.

joshlf and others added 2 commits August 25, 2023 12:12
The only remaining `unsafe` code is used to call SIMD intrinsics.
@tkaitchuck tkaitchuck merged commit a74829b into tkaitchuck:master Oct 20, 2023
7 checks passed
@joshlf joshlf deleted the remove-unsafe branch October 21, 2023 04:02
@@ -125,10 +123,9 @@ pub(crate) fn aesenc(value: u128, xor: u128) -> u128 {
use core::arch::aarch64::*;
#[cfg(target_arch = "arm")]
use core::arch::arm::*;
use core::mem::transmute;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe #170 is caused by this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it. A fix has been uploaded: #171

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That we accidentally left one core::mem::transmute call in demonstrates to me that the name of zercopy::transmute! makes its use error-prone unless the transmute! call is moved out of the unsafe block (like in #171), as otherwise it is too easy to call mem::transmute instead, accidentally.

Copy link

@briansmith briansmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely support the goal to reduce unsafe usage. And I think zerocopy is one of the most carefully-written and best-engineered crates in the ecosystem. But, by its nature it operates at the very edge of the memory safety boundary. I do think it is worth trying a dependency-free approach to the same improvements. I suggest some concrete changes along these lines above (below?). I hope soon the portable SIMD project will make most of this moot.

@@ -7,13 +7,13 @@ macro_rules! convert {
impl Convert<$b> for $a {
#[inline(always)]
fn convert(self) -> $b {
unsafe { core::mem::transmute::<$a, $b>(self) }
zerocopy::transmute!(self)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at how convert! is used and I believe that all uses of it could be replaced with relatively straightforward use of u{64,32,16}::{from,to}_ne_bytes and array pattern matching, with 100% safe Rust code, without performance costs, and without a significant net LoC increase. IMO this is better than taking a zerocopy dependency (this is what I did in ring).

}
}
impl Convert<$a> for $b {
#[inline(always)]
fn convert(self) -> $a {
unsafe { core::mem::transmute::<$b, $a>(self) }
zerocopy::transmute!(self)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

middle.to_vec()
};
use zerocopy::AsBytes;
let array = combination.as_slice().as_bytes().to_vec();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is test-only code, and clearly so, so IMO it would have been fine to leave it as it was. Or, alternatively, zerocopy as a dev-dependency would make sense.

@@ -55,8 +56,7 @@ pub(crate) fn shuffle(a: u128) -> u128 {
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
use core::mem::transmute;
unsafe { transmute(_mm_shuffle_epi8(transmute(a), transmute(SHUFFLE_MASK))) }
unsafe { transmute!(_mm_shuffle_epi8(transmute!(a), transmute!(SHUFFLE_MASK))) }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This didn't reduce the scope of unsafe like #171.

IDK if you run into performance issues doing so, but I would investigate doing something like:

#[cfg(target_arch = "x86_64")]
type Vector = __m128;
#[inline(always)]
const fn scalar(x: Vector) -> u128 {
    unsafe { transmute(x) }
}
#[inline(always)]
const fn vector(x: u128) -> Vector {
    unsafe { transmute(x) }
}
const SHUFFLE_MASK: Vector = vector(SHUFFLE_MASK);
let a = vector(a);
scalar(unsafe { _mm_shuffle_epi8(a, SHUFFLE_MASK) })

IMO, this meets the goal of clarifying that the unsafe conversions are safe with minimal work, without a dependency.

@@ -125,10 +123,9 @@ pub(crate) fn aesenc(value: u128, xor: u128) -> u128 {
use core::arch::aarch64::*;
#[cfg(target_arch = "arm")]
use core::arch::arm::*;
use core::mem::transmute;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That we accidentally left one core::mem::transmute call in demonstrates to me that the name of zercopy::transmute! makes its use error-prone unless the transmute! call is moved out of the unsafe block (like in #171), as otherwise it is too easy to call mem::transmute instead, accidentally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants