Movatterモバイル変換


[0]ホーム

URL:


unsafe

Keywordunsafe 

Source
Expand description

Code or interfaces whosememory safety cannot be verified by the typesystem.

Theunsafe keyword has two uses:

  • to declare the existence of contracts the compiler can’t check (unsafe fn andunsafe trait),
  • and to declare that a programmer has checked that these contracts have been upheld (unsafe {} andunsafe impl, but alsounsafe fn – see below).

§Unsafe abilities

No matter what, Safe Rust can’t cause Undefined Behavior. This isreferred to assoundness: a well-typed program actually has the desiredproperties. TheNomicon has a more detailed explanationon the subject.

To ensure soundness, Safe Rust is restricted enough that it can beautomatically checked. Sometimes, however, it is necessary to write codethat is correct for reasons which are too clever for the compiler tounderstand. In those cases, you need to use Unsafe Rust.

Here are the abilities Unsafe Rust has in addition to Safe Rust:

However, this extra power comes with extra responsibilities: it is now up toyou to ensure soundness. Theunsafe keyword helps by clearly marking thepieces of code that need to worry about this.

§The different meanings ofunsafe

Not all uses ofunsafe are equivalent: some are here to mark the existenceof a contract the programmer must check, others are to say “I have checkedthe contract, go ahead and do this”. The followingdiscussion on Rust Internals has more in-depth explanations about this buthere is a summary of the main points:

  • unsafe fn: calling this function means abiding by a contract thecompiler cannot enforce.
  • unsafe trait: implementing thetrait means abiding by acontract the compiler cannot enforce.
  • unsafe {}: the contract necessary to call the operations inside theblock has been checked by the programmer and is guaranteed to be respected.
  • unsafe impl: the contract necessary to implement the trait has beenchecked by the programmer and is guaranteed to be respected.

See theRustonomicon and theReference for more information.

§Examples

§Marking elements asunsafe

unsafe can be used on functions. Note that functions and statics declaredinextern blocks are implicitly marked asunsafe (but not functionsdeclared asextern "something" fn ...). Mutable statics are always unsafe,wherever they are declared. Methods can also be declared asunsafe:

staticmutFOO:&str ="hello";unsafe fnunsafe_fn() {}unsafe extern"C"{fnunsafe_extern_fn();staticBAR:*mutu32;}traitSafeTraitWithUnsafeMethod {unsafe fnunsafe_method(&self);}structS;implS {unsafe fnunsafe_method_on_struct() {}}

Traits can also be declared asunsafe:

unsafe traitUnsafeTrait {}

Sinceunsafe fn andunsafe trait indicate that there is a safetycontract that the compiler cannot enforce, documenting it is important. Thestandard library has many examples of this, like the following which is anextract fromVec::set_len. The# Safety section explains the contractthat must be fulfilled to safely call the function.

/// Forces the length of the vector to `new_len`.////// This is a low-level operation that maintains none of the normal/// invariants of the type. Normally changing the length of a vector/// is done using one of the safe operations instead, such as/// `truncate`, `resize`, `extend`, or `clear`.////// # Safety////// - `new_len` must be less than or equal to `capacity()`./// - The elements at `old_len..new_len` must be initialized.pub unsafe fnset_len(&mutself, new_len: usize)

§Usingunsafe {} blocks andimpls

Performingunsafe operations requires anunsafe {} block:

#![deny(unsafe_op_in_unsafe_fn)]/// Dereference the given pointer.////// # Safety////// `ptr` must be aligned and must not be dangling.unsafe fnderef_unchecked(ptr:*consti32) -> i32 {// SAFETY: the caller is required to ensure that `ptr` is aligned and dereferenceable.unsafe{*ptr }}leta =3;letb =&aas*const_;// SAFETY: `a` has not been dropped and references are always aligned,// so `b` is a valid address.unsafe{assert_eq!(*b, deref_unchecked(b)); };

§unsafe and traits

The interactions ofunsafe and traits can be surprising, so let us contrast thetwo combinations of safefn inunsafe trait andunsafe fn in safe trait using twoexamples:

/// # Safety////// `make_even` must return an even number.unsafe traitMakeEven {fnmake_even(&self) -> i32;}// SAFETY: Our `make_even` always returns something even.unsafe implMakeEvenfori32 {fnmake_even(&self) -> i32 {self<<1}}fnuse_make_even(x:implMakeEven) {ifx.make_even() %2==1{// SAFETY: this can never happen, because all `MakeEven` implementations        // ensure that `make_even` returns something even.unsafe{ std::hint::unreachable_unchecked() };    }}

Note how the safety contract of the trait is upheld by the implementation, and is itself used touphold the safety contract of the unsafe functionunreachable_unchecked called byuse_make_even.make_even itself is a safe function because itscallers do not have toworry about any contract, only theimplementation ofMakeEven is required to uphold acertain contract.use_make_even is safe because it can use the promise made byMakeEvenimplementations to uphold the safety contract of theunsafe fn unreachable_unchecked it calls.

It is also possible to haveunsafe fn in a regular safetrait:

#![deny(unsafe_op_in_unsafe_fn)]traitIndexable {constLEN: usize;/// # Safety    ///    /// The caller must ensure that `idx < LEN`.unsafe fnidx_unchecked(&self, idx: usize) -> i32;}// The implementation for `i32` doesn't need to do any contract reasoning.implIndexablefori32 {constLEN: usize =1;/// See `Indexable` for the safety contract.unsafe fnidx_unchecked(&self, idx: usize) -> i32 {debug_assert_eq!(idx,0);*self}}// The implementation for arrays exploits the function contract to// make use of `get_unchecked` on slices and avoid a run-time check.implIndexablefor[i32;42] {constLEN: usize =42;/// See `Indexable` for the safety contract.unsafe fnidx_unchecked(&self, idx: usize) -> i32 {// SAFETY: As per this trait's documentation, the caller ensures        // that `idx < 42`.unsafe{*self.get_unchecked(idx) }    }}// The implementation for the never type declares a length of 0,// which means `idx_unchecked` can never be called.implIndexablefor ! {constLEN: usize =0;/// See `Indexable` for the safety contract.unsafe fnidx_unchecked(&self, idx: usize) -> i32 {// SAFETY: As per this trait's documentation, the caller ensures        // that `idx < 0`, which is impossible, so this is dead code.unsafe{ std::hint::unreachable_unchecked() }    }}fnuse_indexable<I: Indexable>(x: I, idx: usize) -> i32 {ifidx < I::LEN {// SAFETY: We have checked that `idx < I::LEN`.unsafe{ x.idx_unchecked(idx) }    }else{panic!("index out-of-bounds")    }}

This time,use_indexable is safe because it uses a run-time check to discharge the safetycontract ofidx_unchecked. ImplementingIndexable is safe because when writingidx_unchecked, we don’t have to worry: ourcallers need to discharge a proof obligation(likeuse_indexable does), but theimplementation ofget_unchecked has no proof obligationto contend with. Of course, the implementation may choose to call other unsafe operations, andthen it needs anunsafeblock to indicate it discharged the proof obligations of itscallees. For that purpose it can make use of the contract that all its callers must uphold –the fact thatidx < LEN.

Note that unlike normalunsafe fn, anunsafe fn in a trait implementation does not get tojust pick an arbitrary safety contract! Ithas to use the safety contract defined by the trait(or one with weaker preconditions).

Formally speaking, anunsafe fn in a trait is a function withpreconditions that go beyondthose encoded by the argument types (such asidx < LEN), whereas anunsafe trait can declarethat some of its functions havepostconditions that go beyond those encoded in the return type(such as returning an even integer). If a trait needs a function with both extra preconditionand extra postcondition, then it needs anunsafe fn in anunsafe trait.


[8]ページ先頭

©2009-2026 Movatter.jp