Skip to content

callback passed to bsearch is missliced #474

Description

@Pipi9221

[llvm-slicer] callback passed to bsearch is missliced (definition dropped, symbol unresolved)

Hi, thanks for maintaining dg and llvm-slicer.
We may have found a slicing correctness issue and wanted to report it with a
minimal reproducer below.

Summary

For a program using bsearch with a callback comparator, slicing with
-c __assert_fail changes module correctness: the sliced IR keeps the
bsearch(..., @cmp) use-site, but drops the cmp function body (leaving only
a declaration). The sliced program then fails to run due to unresolved symbol.

This is a semantic/runtime regression introduced by slicing
(orig PASS, unsliced-bc 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 x86_64 (WSL2)

Minimal Reproducer

#include <assert.h>
#include <stdlib.h>

static int cmp(const void *a, const void *b) {
  int x = *(const int *)a, y = *(const int *)b;
  return (x > y) - (x < y);
}

int main(void) {
  int v[4] = {1, 2, 4, 9};
  int key = 4;
  int *p = (int *)bsearch(&key, v, 4, sizeof(int), cmp);
  assert(p && *p == 4);
  return 0;
}

Reproduction Steps

cat > /tmp/min_callback_escape_bsearch.c <<'EOF'
#include <assert.h>
#include <stdlib.h>

static int cmp(const void *a, const void *b) {
  int x = *(const int *)a, y = *(const int *)b;
  return (x > y) - (x < y);
}

int main(void) {
  int v[4] = {1, 2, 4, 9};
  int key = 4;
  int *p = (int *)bsearch(&key, v, 4, sizeof(int), cmp);
  assert(p && *p == 4);
  return 0;
}
EOF

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

llvm-slicer -c __assert_fail /tmp/min_callback_escape_bsearch.bc -o /tmp/min_callback_escape_bsearch.sliced.bc
lli-14 /tmp/min_callback_escape_bsearch.sliced.bc

Actual Result

  • Unsliced run passes.
  • Sliced run fails:
JIT session error: Symbols not found: [ cmp ]
lli-14: Failed to materialize symbols: { (main, { main }) }

Expected Result

Slicing should preserve callback definitions that escape through function-pointer
arguments to external calls (here bsearch), or otherwise keep the sliced
module internally consistent and runnable.

IR Evidence

Sliced IR still uses @cmp at call site:

%9 = call i8* @bsearch(..., i32 (i8*, i8*)* noundef @cmp)

but only keeps declaration (definition dropped):

declare dso_local i32 @cmp(i8* noundef, i8* noundef)

This leads to unresolved symbol at runtime.

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