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

Variable debuginfo introduces undefined behaviour #105386

Closed
tmiasko opened this issue Dec 6, 2022 · 2 comments · Fixed by #105482
Closed

Variable debuginfo introduces undefined behaviour #105386

tmiasko opened this issue Dec 6, 2022 · 2 comments · Fixed by #105482
Assignees
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) A-mir-opt-inlining Area: MIR inlining C-bug Category: This is a bug.

Comments

@tmiasko
Copy link
Contributor

tmiasko commented Dec 6, 2022

When generating a variable debuginfo, rustc emits an expression describing the address of a source variable. Since #83941, rustc also evaluates this expression.

The expression can contain indirections, and it is not always valid to evaluate it. Consider a source variable that is described indirectly in terms of a base LocalRef::Place local. The source variable will be introduced at the beginning of a function, but at this point the base local might be uninitialized. For example:

#![feature(stmt_expr_attributes)]
pub struct S([usize; 8]);

#[no_mangle]
pub fn f(x: S, y: S) -> usize {
    (#[inline(always)]|| {
        let _z = x;
        y.0[0]
    })()
}
$ rustc --crate-type=lib c.rs -O -Cdebuginfo=2 -Cno-prepopulate-passes -Zunpretty=mir
...
fn f(_1: S, _2: S) -> usize {
    debug x => _1;                       // in scope 0 at c.rs:5:10: 5:11
    debug y => _2;                       // in scope 0 at c.rs:5:16: 5:17
    let mut _0: usize;                   // return place in scope 0 at c.rs:5:25: 5:30
    let mut _3: [[email protected]:6:23: 6:25]; // in scope 0 at c.rs:6:5: 9:7
    let mut _4: &S;                      // in scope 0 at c.rs:6:5: 9:7
    scope 1 (inlined f::{closure#0}) {   // at c.rs:6:5: 9:9
        debug x => (_3.0: S);            // in scope 1 at c.rs:5:10: 5:11
        debug y => (*(_3.1: &S));        // in scope 1 at c.rs:5:16: 5:17
...
$ rustc --crate-type=lib c.rs -O -Cdebuginfo=2 -Cno-prepopulate-passes --emit llvm-ir
...
%S = type { [8 x i64] }
%"[[email protected]:6:23: 6:25]" = type { %S, ptr }

; Function Attrs: nonlazybind uwtable
define i64 @f(ptr noalias nocapture noundef readonly dereferenceable(64) %x, ptr noalias nocapture noundef readonly dereferenceable(64) %y) unnamed_addr #0 !dbg !6 {
start:
  %_z = alloca %S, align 8
  %_3 = alloca %"[[email protected]:6:23: 6:25]", align 8
  call void @llvm.dbg.declare(metadata ptr %x, metadata !21, metadata !DIExpression()), !dbg !23
  call void @llvm.dbg.declare(metadata ptr %y, metadata !22, metadata !DIExpression()), !dbg !24
  call void @llvm.dbg.declare(metadata ptr %_3, metadata !25, metadata !DIExpression()), !dbg !39
  %0 = getelementptr inbounds %"[[email protected]:6:23: 6:25]", ptr %_3, i32 0, i32 1
  %1 = load ptr, ptr %0, align 8, !nonnull !19, !align !41, !noundef !19
  call void @llvm.dbg.declare(metadata ptr %_3, metadata !36, metadata !DIExpression(DW_OP_plus_uconst, 64, DW_OP_deref)), !dbg !42
  call void @llvm.dbg.declare(metadata ptr %_z, metadata !37, metadata !DIExpression()), !dbg !43
  call void @llvm.lifetime.start.p0(i64 72, ptr %_3), !dbg !40

Note that %1 = load has !nonnull and !noundef metadata but loaded value is uninitialized.

(This leads to end-to-end miscompilation with -Cdebuginfo=2).

cc @wesleywiser, @nagisa #83941

@tmiasko tmiasko added A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-bug Category: This is a bug. A-mir-opt-inlining Area: MIR inlining labels Dec 6, 2022
@tmiasko tmiasko changed the title Variable debuginfo introduces undefined behaviour? Variable debuginfo introduces undefined behaviour Dec 6, 2022
@tmiasko
Copy link
Contributor Author

tmiasko commented Dec 7, 2022

A variant that demonstrates complete end-to-end miscompilation can be found in #105344 (comment).

@wesleywiser wesleywiser self-assigned this Dec 7, 2022
@RalfJung
Copy link
Member

RalfJung commented Dec 8, 2022

Note that %1 = load has !nonnull and !noundef metadata but loaded value is uninitialized.

Even without the metadata, this load could violate noalias constraints. So just removing the metadata is not a proper fix.

EDIT: Or does this always load from an alloca that doesn't have any other pointers to it yet? Then it should be fine in terms of aliasing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) A-mir-opt-inlining Area: MIR inlining C-bug Category: This is a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants