Skip to content

[Mem2reg] exposes UB in untaken branch #154873

@zitongzhoueric

Description

@zitongzhoueric

To reproduce: https://alive2.llvm.org/ce/z/PxBFzh
mem2reg seems to re-expose UB despite the branch accessing uninitialized memory being untaken, as a result the optimized function doesn't properly refine the original and gets flagged by Alive2. I'm not sure if this is an actual problem or just an artifact of the way Alive2 works.

----------------------------------------
define i32 @g(i32 noundef %#0, ptr noundef %#1) {
#2:
  %#6 = alloca i64 4, align 4
  %#7 = alloca i64 8, align 8
  %#8 = alloca i64 8, align 8
  store i32 noundef %#0, ptr %#6, align 4
  store ptr noundef %#1, ptr %#7, align 8
  %#9 = load i32, ptr %#6, align 4
  %#10 = icmp ne i32 %#9, 0
  br i1 %#10, label %#4, label %#3

#3:
  store ptr %#7, ptr %#8, align 8
  br label %#5

#4:
  %#11 = load ptr, ptr %#8, align 8
  %#12 = gep inbounds nuw ptr %#11, 4 x i32 1
  store ptr %#12, ptr %#8, align 8
  br label %#5

#5:
  %#13 = load ptr, ptr %#8, align 8
  %#14 = load i32, ptr %#13, align 4
  ret i32 %#14
}
=>
define i32 @g(i32 noundef %#0, ptr noundef %#1) {
#2:
  %#6 = alloca i64 8, align 8
  store ptr noundef %#1, ptr %#6, align 8
  %#7 = icmp ne i32 noundef %#0, 0
  br i1 %#7, label %#4, label %#3

#3:
  br label %#5

#4:
  %#8 = gep inbounds nuw ptr undef, 4 x i32 1
  br label %#5

#5:
  %.0 = phi ptr [ %#8, %#4 ], [ %#6, %#3 ]
  %#9 = load i32, ptr %.0, align 8
  ret i32 %#9
}
Transformation doesn't verify!

ERROR: Source is more defined than target

Example:
i32 noundef %#0 = #x00000000 (0)
ptr noundef %#1 = null

Source:
ptr %#6 = pointer(local, block_id=0, offset=0) / Address=#x100
ptr %#7 = pointer(local, block_id=1, offset=0) / Address=#x168
ptr %#8 = pointer(local, block_id=2, offset=0) / Address=#x120
i32 %#9 = #x00000000 (0)
i1 %#10 = #x0 (0)
  >> Jump to %#3
  >> Jump to %#5
ptr %#13 = pointer(local, block_id=1, offset=0) / Address=#x168
i32 %#14 = poison

SOURCE MEMORY STATE
===================
NON-LOCAL BLOCKS:
Block 0 >	size: 0	align: 4	alloc type: 0	alive: false	address: 0
Block 1 >	size: 0	align: 2	alloc type: 0	alive: true	address: 8

LOCAL BLOCKS:
Block 4 >	size: 4	align: 4	alloc type: 1	alive: true	address: 256
Block 5 >	size: 8	align: 8	alloc type: 1	alive: true	address: 360
Block 6 >	size: 8	align: 8	alloc type: 1	alive: true	address: 288

Target:
ptr %#6 = pointer(local, block_id=0, offset=0) / Address=#x100
i1 %#7 = #x0 (0)
  >> Jump to %#3
  >> Jump to %#5
ptr %.0 = pointer(local, block_id=0, offset=0) / Address=#x100
i32 %#9 = UB triggered!

TARGET MEMORY STATE
===================
LOCAL BLOCKS:
Block 4 >	size: 8	align: 8	alloc type: 1	alive: true	address: 256


Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors

This is generated from the following C program:

int g ( int c , int * p) { 
    int * t ;
    if ( c ) t ++ ;  // UB is untaken
    else t = & p; 
    return * t; 
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidResolved as invalid, i.e. not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions