Skip to content

Commit 98470c0

Browse files
authored
[clang][bytecode] Handle __builtin_bcmp (#119678)
... the same as `__builtin_memcmp`. Also fix a bug we still had when we couldn't find a difference in the two inputs after `Size` bytes.
1 parent 5013c81 commit 98470c0

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,7 +1917,7 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
19171917
const APSInt &Size =
19181918
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
19191919

1920-
if (ID == Builtin::BImemcmp)
1920+
if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp)
19211921
diagnoseNonConstexprBuiltin(S, OpPC, ID);
19221922

19231923
if (Size.isZero()) {
@@ -1952,15 +1952,34 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
19521952
BufferB.byteSize().getQuantity());
19531953
size_t CmpSize =
19541954
std::min(MinBufferSize, static_cast<size_t>(Size.getZExtValue()));
1955-
int Result = std::memcmp(BufferA.Data.get(), BufferB.Data.get(), CmpSize);
1956-
if (Result == 0)
1955+
1956+
for (size_t I = 0; I != CmpSize; ++I) {
1957+
std::byte A = BufferA.Data[I];
1958+
std::byte B = BufferB.Data[I];
1959+
1960+
if (A < B) {
1961+
pushInteger(S, -1, Call->getType());
1962+
return true;
1963+
} else if (A > B) {
1964+
pushInteger(S, 1, Call->getType());
1965+
return true;
1966+
}
1967+
}
1968+
1969+
// We compared CmpSize bytes above. If the limiting factor was the Size
1970+
// passed, we're done and the result is equality (0).
1971+
if (Size.getZExtValue() <= CmpSize) {
19571972
pushInteger(S, 0, Call->getType());
1958-
else if (Result < 0)
1959-
pushInteger(S, -1, Call->getType());
1960-
else
1961-
pushInteger(S, 1, Call->getType());
1973+
return true;
1974+
}
19621975

1963-
return true;
1976+
// However, if we read all the available bytes but were instructed to read
1977+
// even more, diagnose this as a "read of dereferenced one-past-the-end
1978+
// pointer". This is what would happen if we called CheckRead() on every array
1979+
// element.
1980+
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_past_end)
1981+
<< AK_Read << S.Current->getRange(OpPC);
1982+
return false;
19641983
}
19651984

19661985
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
@@ -2438,6 +2457,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
24382457

24392458
case Builtin::BI__builtin_memcmp:
24402459
case Builtin::BImemcmp:
2460+
case Builtin::BI__builtin_bcmp:
2461+
case Builtin::BIbcmp:
24412462
if (!interp__builtin_memcmp(S, OpPC, Frame, F, Call))
24422463
return false;
24432464
break;

clang/test/AST/ByteCode/builtin-functions.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,4 +1255,19 @@ namespace Memcmp {
12551255
// both-note {{not supported}}
12561256
static_assert(__builtin_memcmp("", &incomplete, 1u) == 42); // both-error {{not an integral constant}} \
12571257
// both-note {{not supported}}
1258+
1259+
static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0banana", 100) == 0); // both-error {{not an integral constant}} \
1260+
// both-note {{dereferenced one-past-the-end}}
1261+
1262+
static_assert(__builtin_bcmp("abaa", "abba", 3) != 0);
1263+
static_assert(__builtin_bcmp("abaa", "abba", 2) == 0);
1264+
static_assert(__builtin_bcmp("a\203", "a", 2) != 0);
1265+
static_assert(__builtin_bcmp("a\203", "a\003", 2) != 0);
1266+
static_assert(__builtin_bcmp(0, 0, 0) == 0);
1267+
static_assert(__builtin_bcmp("abab\0banana", "abab\0banana", 100) == 0); // both-error {{not an integral constant}}\
1268+
// both-note {{dereferenced one-past-the-end}}
1269+
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 100) != 0); // FIXME: Should we reject this?
1270+
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0);
1271+
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 6) != 0);
1272+
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 5) == 0);
12581273
}

0 commit comments

Comments
 (0)