Skip to content

Optimisation-caused UB during cross-crate compilation #76387

Closed
@inikulin

Description

@inikulin

The issue reproduces only if FatPtr code resides in a separate crate and only if compiled in release configuration.

I tried this code:

fat_ptr's crate lib.rs:

pub struct FatPtr {
    ptr: *mut u8,
    len: usize,
}

impl FatPtr {
    pub fn new(len: usize) -> FatPtr {
        let ptr = Box::into_raw(vec![42u8; len].into_boxed_slice()) as *mut u8;

        FatPtr { ptr, len }
    }
}

impl std::ops::Deref for FatPtr {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
    }
}

impl std::ops::Drop for FatPtr {
    fn drop(&mut self) {
        println!("Drop");
    }
}

test's crate main.rs:

use fat_ptr::FatPtr;

fn print(data: &[u8]) {
    println!("{:#?}", data);
}

fn main() {
    let ptr = FatPtr::new(20);
    let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr(), ptr.len()) };

    print(data);
}

I expected to see this happen: 42 printed 20 times.

Instead, this happened: 42 printed 20 times in debug build, but not in release. Instead, slice length appears to be corrupted, so println prints memory dump outside of allocated slice and eventually segfaults. However, if Drop implementation for FatPtr is removed, then slice is truncated to a single byte, which is still incorrect, but doesn't crash the process.

If print(data) call is replaced with println!("{:#?}", data); directly then everything works as intended even on release builds. If FatPtr code placed in the same crate as main then everything works as intended as well. Removing #[inline] from deref fixed the issue as well.

This reproduces on Linux and MacOS (haven't tried Windows).

Meta

rustc --version --verbose:

rustc 1.46.0 (04488afe3 2020-08-24)
binary: rustc
commit-hash: 04488afe34512aa4c33566eb16d8c912a3ae04f9
commit-date: 2020-08-24
host: x86_64-apple-darwin
release: 1.46.0
LLVM version: 10.0
Backtrace

N/A

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-codegenArea: Code generationC-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-criticalCritical priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions