Skip to content

Bytecode interpreter: comparing pointers behave differently than ExprConstant #172165

@hanickadot

Description

@hanickadot

(I'm not really experienced with the bytecode interpreter, but this seems to me as a bug)

https://compiler-explorer.com/z/vWsW99vW9

Following code works in the AST interpreter in Clang, GCC, EDG, all three static asserts fails in the ByteCode interpreter. (MSVC fails on last two)

struct tuple {
  int a;
  int b;
};

constexpr tuple tpl{1,2};

// start of the object VS first member
static_assert(static_cast<const void *>(&tpl) == static_cast<const void *>(&tpl.a)); // bytecode fail
// past the first member VS second member
static_assert(static_cast<const void *>(&tpl.a+1) == static_cast<const void *>(&tpl.b)); // bytecode and MSVC fail
// past the second member VS past the object
static_assert(static_cast<const void *>(&tpl.b+1) == static_cast<const void *>(&tpl+1)); // bytecode and MSVC fail

If I do similar code but in runtime:
https://compiler-explorer.com/z/9KdbceaGq (with constexpr compare function)

#include <cassert>

struct tuple {
  int a;
  int b;
};

constexpr bool compare(const void * a, const void * b) {
    return a == b;
}

int main() {
  tuple tpl{1,2};

  // start of the object VS first member
  assert(compare(&tpl, &tpl.a));
  // past the first member VS second member
  assert(compare(&tpl.a+1, &tpl.b));
  // past the second member VS past the object
  assert(compare(&tpl.b+1, &tpl+1));
}

Now the runtime code with byte code interpreter crashes on assert's check which is pre-calculated with the bytecode interpreter.

Removing constexpr on compare, will make it work in runtime:
https://compiler-explorer.com/z/z91nYhe9Y

#include <cassert>

struct tuple {
  int a;
  int b;
};

bool compare(const void * a, const void * b) { // no constexpr here
    return a == b;
}

int main() {
  tuple tpl{1,2};

  // start of the object VS first member
  assert(compare(&tpl, &tpl.a));
  // past the first member VS second member
  assert(compare(&tpl.a+1, &tpl.b));
  // past the second member VS past the object
  assert(compare(&tpl.b+1, &tpl+1));
}

It seems problem is in clang/lib/AST/ByteCode/Interp.h

if (Pointer::hasSameBase(LHS, RHS)) {
size_t A = LHS.computeOffsetForComparison();
size_t B = RHS.computeOffsetForComparison();
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(A, B))));
return true;
Where comparison is done thru offsets, but for some reason the first member has offset 16 and not 0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:bytecodeIssues for the clang bytecode constexpr interpreter

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions