-
Notifications
You must be signed in to change notification settings - Fork 141
[llvm-slicer] memmove source init sliced away #471
Description
@mchalupa Hi, thanks for maintaining dg
I may have found a slicing correctness issue and wanted to report it with a minimal reproducer below.
[llvm-slicer] memmove source initialization is sliced away under -c __assert_fail (semantic regression)
Summary
Slicing with criterion __assert_fail can keep llvm.memmove but remove the prior
llvm.memcpy that initializes its source bytes. The sliced program then reads
uninitialized memory and fails an assertion, while the original/unsliced program
passes.
This is a semantic regression introduced by slicing (orig PASS, sliced FAIL).
Environment
- dg commit:
dc3615d03fedfce62f37604b45d22e31c9d7e557 - slicer:
llvm-slicer(built from this dg checkout) - clang:
Ubuntu clang version 14.0.0-1ubuntu1.1 - lli:
Ubuntu LLVM version 14.0.0 - OS:
Linux ... WSL2 x86_64(kernel5.15.167.4-microsoft-standard-WSL2)
Minimal Reproducer
#include <assert.h>
#include <string.h>
int main(void) {
char src[] = "hello";
char buf[16];
if (1) {
memcpy(buf, src, 6);
memmove(buf + 2, buf, 3);
}
if (0) {
buf[0] = 'x';
}
int probe_ok = (buf[2] == 'h' && buf[3] == 'e' && buf[4] == 'l');
assert(probe_ok);
return 0;
}Reproduction Steps
cat > /tmp/min_memmove_deadcode.c <<'EOF'
#include <assert.h>
#include <string.h>
int main(void) {
char src[] = "hello";
char buf[16];
if (1) {
memcpy(buf, src, 6);
memmove(buf + 2, buf, 3);
}
if (0) {
buf[0] = 'x';
}
int probe_ok = (buf[2] == 'h' && buf[3] == 'e' && buf[4] == 'l');
assert(probe_ok);
return 0;
}
EOF
clang-14 -O0 -g -c -emit-llvm /tmp/min_memmove_deadcode.c -o /tmp/min_memmove_deadcode.bc
lli-14 /tmp/min_memmove_deadcode.bc
llvm-slicer -c __assert_fail /tmp/min_memmove_deadcode.bc -o /tmp/min_memmove_deadcode.sliced.bc
lli-14 /tmp/min_memmove_deadcode.sliced.bcActual Result
lli-14 /tmp/min_memmove_deadcode.bcpasses.lli-14 /tmp/min_memmove_deadcode.sliced.bcfails:
Assertion `probe_ok' failed.
Expected Result
The slice should preserve all dependencies relevant to __assert_fail reachability
and condition evaluation. This example should not become failing after slicing.
IR Evidence
Original IR contains:
call void @llvm.memcpy.p0i8.p0i8.i64(..., i64 6, ...)
call void @llvm.memcpy.p0i8.p0i8.i64(..., i64 6, ...)
call void @llvm.memmove.p0i8.p0i8.i64(..., i64 3, ...)Sliced IR contains only:
call void @llvm.memmove.p0i8.p0i8.i64(..., i64 3, ...)The source-initializing memcpy is removed, so memmove reads uninitialized bytes.
Why this looks like a slicer bug
probe_ok depends on buf[2..4], which are written by memmove(buf+2, buf, 3).
Those values depend on buf[0..2], which are defined by the prior memcpy.
Dropping that initialization breaks memory data dependencies and changes semantics.