Skip to content

strncat side-effect call is sliced away #472

Description

@Pipi9221

[llvm-slicer] strncat side-effect call is sliced away

Summary

When slicing with criteria that should keep the value flow to an assertion
condition, strncat can be removed while strcmp/assert are kept.

This changes semantics (orig PASS, sliced FAIL): destination buffer content
is no longer updated, but the check that expects updated content remains.

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 (kernel 5.15.167.4-microsoft-standard-WSL2)

Minimal Reproducer

#include <assert.h>
#include <string.h>

int main(void) {
    char buf[16] = "abc";

    if (0) {
        strcat(buf, "dead");
    }

    strncat(buf, "XYZ", 3);

    int probe_ok = (strcmp(buf, "abcXYZ") == 0);
    assert(probe_ok);
    return 0;
}

Reproduction Steps

cat > /tmp/min_strncat_deadcode.c <<'EOF'
#include <assert.h>
#include <string.h>
int main(void) {
    char buf[16] = "abc";
    if (0) {
        strcat(buf, "dead");
    }
    strncat(buf, "XYZ", 3);
    int probe_ok = (strcmp(buf, "abcXYZ") == 0);
    assert(probe_ok);
    return 0;
}
EOF

clang-14 -O0 -g -c -emit-llvm /tmp/min_strncat_deadcode.c -o /tmp/min_strncat_deadcode.bc
lli-14 /tmp/min_strncat_deadcode.bc

# either criterion reproduces:
llvm-slicer -c __assert_fail /tmp/min_strncat_deadcode.bc -o /tmp/min_strncat_deadcode.assert.sliced.bc
lli-14 /tmp/min_strncat_deadcode.assert.sliced.bc

llvm-slicer -c 14:probe_ok /tmp/min_strncat_deadcode.bc -o /tmp/min_strncat_deadcode.line.sliced.bc
lli-14 /tmp/min_strncat_deadcode.line.sliced.bc

Actual Result

  • Unsliced run passes.
  • Sliced runs fail with assertion abort:
Assertion `probe_ok' failed.

Expected Result

Slicing should preserve effects needed to compute the criterion-dependent
condition. In this program, strncat should not be removed when strcmp/assert
remain in the slice.

IR Evidence

Original IR contains:

%6 = call i8* @strncat(...)
%8 = call i32 @strcmp(...)
call void @__assert_fail(...)

Sliced IR contains:

%5 = call i32 @strcmp(...)
call void @__assert_fail(...)

strncat is removed, but the check that depends on its buffer write is still
present.

Additional Diagnostic

Using --undefined-funs=rw-args keeps strncat in the slice and the sliced
program passes for this reproducer, which suggests the issue is related to
missing side-effect modeling for this external call under default settings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions