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

llvm error: cfi: Assertion cast<DISubprogram>(Scope)->describes(&MF->getFunction())` #119951

Open
matthiaskrgr opened this issue Jan 14, 2024 · 2 comments
Labels
A-sanitizers Area: Sanitizers for correctness and code quality. C-bug Category: This is a bug. I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ PG-exploit-mitigations Project group: Exploit mitigations requires-debug-assertions This issue requires debug-assertions in some way T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@matthiaskrgr
Copy link
Member

snippet:

use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicUsize};
use std::thread::spawn;

fn static_atomic(val: usize) -> &'static AtomicUsize {
    let ret = Box::leak(Box::new(AtomicUsize::new(val)));
    ret
}

fn relaxed() -> bool {
    let x = static_atomic(0);

    let j2 = spawn(move || x.load(Relaxed));

    let r2 = j2.join().unwrap();

    r2 == 1
}

fn seq_cst() -> bool {
    let x = static_atomic(0);

    let j3 = spawn(move || x.load(SeqCst));

    let r3 = j3.join().unwrap();

    r3 == 1
}

fn initialization_write(add_fence: bool) -> bool {
    let x = static_atomic(11);

    let j2 = spawn(move || x.load(Relaxed));

    let r2 = j2.join().unwrap();

    r2 == 11
}

fn assert_once(f: fn() -> bool) {
    assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x));
}

pub fn main() {
    assert_once(relaxed);
    assert_once(seq_cst);
    assert_once(|| initialization_write(false));
}

Version information

rustc 1.77.0-dev
binary: rustc
commit-hash: unknown
commit-date: unknown
host: x86_64-unknown-linux-gnu
release: 1.77.0-dev
LLVM version: 17.0.6

Command:
/home/matthias/.rustup/toolchains/local-debug-assertions/bin/rustc -Zmir-opt-level=3 -Cdebuginfo=2 -Copt-level=3 -Zsanitizer=cfi -Ccodegen-units=1 -Clto -ocodegen -Zsanitizer-cfi-normalize-integers --edition=2015

Program output

warning: unused import: `fence`
 --> /tmp/icemaker_global_tempdir.18GTkKSaGL4b/rustc_testrunner_tmpdir_reporting.PLKsBwe60BMh/mvce.rs:2:25
  |
2 | use std::sync::atomic::{fence, AtomicUsize};
  |                         ^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused variable: `add_fence`
  --> /tmp/icemaker_global_tempdir.18GTkKSaGL4b/rustc_testrunner_tmpdir_reporting.PLKsBwe60BMh/mvce.rs:30:25
   |
30 | fn initialization_write(add_fence: bool) -> bool {
   |                         ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_add_fence`
   |
   = note: `#[warn(unused_variables)]` on by default

inlinable function call in a function with debug info must have a !dbg location
  %34 = tail call noundef zeroext i1 @_ZN4core3ops8function6FnOnce9call_once17h0a5cef41d9043f5eE(), !noalias !6817
inlinable function call in a function with debug info must have a !dbg location
  %34 = tail call noundef zeroext i1 @_ZN4core3ops8function6FnOnce9call_once17h0a5cef41d9043f5eE(), !noalias !6816
LLVM ERROR: Broken module found, compilation aborted!

@matthiaskrgr matthiaskrgr added I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. PG-exploit-mitigations Project group: Exploit mitigations labels Jan 14, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jan 14, 2024
@matthiaskrgr
Copy link
Member Author

longer version:

//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0

// Tests showing weak memory behaviours are exhibited. All tests
// return true when the desired behaviour is seen.
// This is scheduler and pseudo-RNG dependent, so each test is
// run multiple times until one try returns true.
// Spurious failure is possible, if you are really unlucky with
// the RNG and always read the latest value from the store buffer.

use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicUsize};
use std::thread::spawn;

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

// We can't create static items because we need to run each test
// multiple times
fn static_atomic(val: usize) -> &'static AtomicUsize {
    let ret = Box::leak(Box::new(AtomicUsize::new(val)));
    ret
}

// Spins until it reads the given value
fn reads_value(loc: &AtomicUsize, val: usize) -> usize {
    while loc.load(Relaxed) != val {
        std::hint::spin_loop();
    }
    val
}

fn relaxed() -> bool {
    let x = static_atomic(0);
    let j1 = spawn(move || {
        x.store(1, Relaxed);
        x.store(2, Relaxed);
    });

    let j2 = spawn(move || x.load(Relaxed));

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    r2 == 1
}

// https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf Figure 8
fn seq_cst() -> bool {
    let x = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
    });

    let j2 = spawn(move || {
        x.store(2, SeqCst);
        x.store(3, SeqCst);
    });

    let j3 = spawn(move || x.load(SeqCst));

    j1.join().unwrap();
    j2.join().unwrap();
    let r3 = j3.join().unwrap();

    r3 == 1
}

fn initialization_write(add_fence: bool) -> bool {
    let x = static_atomic(11);
    assert_eq!(x.load(Relaxed), 11); // work around https://github.com/rust-lang/miri/issues/2164

    let wait = static_atomic(0);

    let j1 = spawn(move || {
        x.store(22, Relaxed);
        // Relaxed is intentional. We want to test if the thread 2 reads the initialisation write
        // after a relaxed write
        wait.store(1, Relaxed);
    });

    let j2 = spawn(move || {
        reads_value(wait, 1);
        if add_fence {
            fence(AcqRel);
        }
        x.load(Relaxed)
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    r2 == 11
}

fn faa_replaced_by_load() -> bool {
    // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905
    #[no_mangle]
    pub fn rdmw(storing: &AtomicUsize, sync: &AtomicUsize, loading: &AtomicUsize) -> usize {
        storing.store(1, Relaxed);
        fence(Release);
        // sync.fetch_add(0, Relaxed);
        sync.load(Relaxed);
        fence(Acquire);
        loading.load(Relaxed)
    }

    let x = static_atomic(0);
    assert_eq!(x.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164
    let y = static_atomic(0);
    assert_eq!(y.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164
    let z = static_atomic(0);
    assert_eq!(z.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164

    // Since each thread is so short, we need to make sure that they truely run at the same time
    // Otherwise t1 will finish before t2 even starts
    let go = static_atomic(0);

    let t1 = spawn(move || {
        while go.load(Relaxed) == 0 {}
        rdmw(y, x, z)
    });

    let t2 = spawn(move || {
        while go.load(Relaxed) == 0 {}
        rdmw(z, x, y)
    });

    go.store(1, Relaxed);

    let a = t1.join().unwrap();
    let b = t2.join().unwrap();
    (a, b) == (0, 0)
}

/// Asserts that the function returns true at least once in 100 runs
fn assert_once(f: fn() -> bool) {
    assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x));
}

pub fn main() {
    assert_once(relaxed);
    assert_once(seq_cst);
    assert_once(|| initialization_write(false));
    assert_once(|| initialization_write(true));
    assert_once(faa_replaced_by_load);
}
!dbg attachment points at wrong subprogram for function
!14215 = distinct !DISubprogram(name: "main", linkageName: "_ZN4weak4main17h5f1de778f0552bf3E", scope: !230, file: !1443, line: 144, type: !949, scopeLine: 144, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized | DISPFlagMainSubprogram, unit: !803, templateParams: !52)
ptr @_ZN4weak4main17h5f1de778f0552bf3E.cfi
  call void @llvm.dbg.declare(metadata ptr poison, metadata !5504, metadata !DIExpression()), !dbg !5512
!5512 = !DILocation(line: 250, column: 5, scope: !5498)
!5498 = distinct !DISubprogram(name: "call_once<weak::main::{closure_env#0}, ()>", linkageName: "_ZN4core3ops8function6FnOnce9call_once17h5cb9833c3bed92bfE", scope: !1796, file: !1795, line: 250, type: !5499, scopeLine: 250, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !803, templateParams: !5506, retainedNodes: !5503)
!5498 = distinct !DISubprogram(name: "call_once<weak::main::{closure_env#0}, ()>", linkageName: "_ZN4core3ops8function6FnOnce9call_once17h5cb9833c3bed92bfE", scope: !1796, file: !1795, line: 250, type: !5499, scopeLine: 250, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !803, templateParams: !5506, retainedNodes: !5503)
conflicting debug info for argument
  call void @llvm.dbg.declare(metadata ptr poison, metadata !5527, metadata !DIExpression()), !dbg !5535
!5504 = !DILocalVariable(arg: 1, scope: !5498, file: !1795, line: 250, type: !5501)
!5527 = !DILocalVariable(arg: 1, scope: !5522, file: !1795, line: 250, type: !5525)
conflicting debug info for argument
  call void @llvm.dbg.declare(metadata ptr undef, metadata !5528, metadata !DIExpression()), !dbg !5535
!5505 = !DILocalVariable(arg: 2, scope: !5498, file: !1795, line: 250, type: !7)
!5528 = !DILocalVariable(arg: 2, scope: !5522, file: !1795, line: 250, type: !7)
!dbg attachment points at wrong subprogram for function
!14215 = distinct !DISubprogram(name: "main", linkageName: "_ZN4weak4main17h5f1de778f0552bf3E", scope: !230, file: !1443, line: 144, type: !949, scopeLine: 144, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized | DISPFlagMainSubprogram, unit: !803, templateParams: !52)
ptr @_ZN4weak4main17h5f1de778f0552bf3E.cfi
  call void @llvm.dbg.declare(metadata ptr poison, metadata !5504, metadata !DIExpression()), !dbg !5512
!5512 = !DILocation(line: 250, column: 5, scope: !5498)
!5498 = distinct !DISubprogram(name: "call_once<weak::main::{closure_env#0}, ()>", linkageName: "_ZN4core3ops8function6FnOnce9call_once17h5cb9833c3bed92bfE", scope: !1796, file: !1795, line: 250, type: !5499, scopeLine: 250, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !803, templateParams: !5506, retainedNodes: !5503)
!5498 = distinct !DISubprogram(name: "call_once<weak::main::{closure_env#0}, ()>", linkageName: "_ZN4core3ops8function6FnOnce9call_once17h5cb9833c3bed92bfE", scope: !1796, file: !1795, line: 250, type: !5499, scopeLine: 250, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !803, templateParams: !5506, retainedNodes: !5503)
conflicting debug info for argument
  call void @llvm.dbg.declare(metadata ptr poison, metadata !5527, metadata !DIExpression()), !dbg !5535
!5504 = !DILocalVariable(arg: 1, scope: !5498, file: !1795, line: 250, type: !5501)
!5527 = !DILocalVariable(arg: 1, scope: !5522, file: !1795, line: 250, type: !5525)
conflicting debug info for argument
  call void @llvm.dbg.declare(metadata ptr undef, metadata !5528, metadata !DIExpression()), !dbg !5535
!5505 = !DILocalVariable(arg: 2, scope: !5498, file: !1795, line: 250, type: !7)
!5528 = !DILocalVariable(arg: 2, scope: !5522, file: !1795, line: 250, type: !7)
rustc: /home/matthias/vcs/github/rust_debug_assertions/src/llvm-project/llvm/lib/CodeGen/LexicalScopes.cpp:178: LexicalScope *llvm::LexicalScopes::getOrCreateRegularScope(const DILocalScope *): Assertion `cast<DISubprogram>(Scope)->describes(&MF->getFunction())' failed.
[1]    848450 IOT instruction  ~/.rustup/toolchains/local-debug-assertions/bin/rustc  -Zmir-opt-level=3

@matthiaskrgr matthiaskrgr added the requires-debug-assertions This issue requires debug-assertions in some way label Jan 14, 2024
@matthiaskrgr matthiaskrgr changed the title ICE: cfi: Assertion cast<DISubprogram>(Scope)->describes(&MF->getFunction())` llvm error: cfi: Assertion cast<DISubprogram>(Scope)->describes(&MF->getFunction())` Jan 14, 2024
@saethlin saethlin removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jan 14, 2024
@Jules-Bertholet
Copy link
Contributor

@rustbot label A-sanitizers

@rustbot rustbot added the A-sanitizers Area: Sanitizers for correctness and code quality. label Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-sanitizers Area: Sanitizers for correctness and code quality. C-bug Category: This is a bug. I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ PG-exploit-mitigations Project group: Exploit mitigations requires-debug-assertions This issue requires debug-assertions in some way T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants