-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[clang][bytecode] Handle __builtin_bcmp #119678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
... 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.
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) Changes... the same as Full diff: https://github.com/llvm/llvm-project/pull/119678.diff 2 Files Affected:
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index a343280b5ce50f..21baedf832eeac 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1917,7 +1917,7 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
- if (ID == Builtin::BImemcmp)
+ if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp)
diagnoseNonConstexprBuiltin(S, OpPC, ID);
if (Size.isZero()) {
@@ -1952,15 +1952,34 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
BufferB.byteSize().getQuantity());
size_t CmpSize =
std::min(MinBufferSize, static_cast<size_t>(Size.getZExtValue()));
- int Result = std::memcmp(BufferA.Data.get(), BufferB.Data.get(), CmpSize);
- if (Result == 0)
+
+ for (size_t I = 0; I != CmpSize; ++I) {
+ std::byte A = BufferA.Data[I];
+ std::byte B = BufferB.Data[I];
+
+ if (A < B) {
+ pushInteger(S, -1, Call->getType());
+ return true;
+ } else if (A > B) {
+ pushInteger(S, 1, Call->getType());
+ return true;
+ }
+ }
+
+ // We compared CmpSize bytes above. If the limiting factor was the Size
+ // passed, we're done and the result is equality (0).
+ if (Size.getZExtValue() <= CmpSize) {
pushInteger(S, 0, Call->getType());
- else if (Result < 0)
- pushInteger(S, -1, Call->getType());
- else
- pushInteger(S, 1, Call->getType());
+ return true;
+ }
- return true;
+ // However, if we read all the available bytes but were instructed to read
+ // even more, diagnose this as a "read of dereferenced one-past-the-end
+ // pointer". This is what would happen if we called CheckRead() on every array
+ // element.
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_past_end)
+ << AK_Read << S.Current->getRange(OpPC);
+ return false;
}
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
@@ -2438,6 +2457,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_memcmp:
case Builtin::BImemcmp:
+ case Builtin::BI__builtin_bcmp:
+ case Builtin::BIbcmp:
if (!interp__builtin_memcmp(S, OpPC, Frame, F, Call))
return false;
break;
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 83caa1d03df3a3..4ee24646286fa8 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -1255,4 +1255,19 @@ namespace Memcmp {
// both-note {{not supported}}
static_assert(__builtin_memcmp("", &incomplete, 1u) == 42); // both-error {{not an integral constant}} \
// both-note {{not supported}}
+
+ static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0banana", 100) == 0); // both-error {{not an integral constant}} \
+ // both-note {{dereferenced one-past-the-end}}
+
+ static_assert(__builtin_bcmp("abaa", "abba", 3) != 0);
+ static_assert(__builtin_bcmp("abaa", "abba", 2) == 0);
+ static_assert(__builtin_bcmp("a\203", "a", 2) != 0);
+ static_assert(__builtin_bcmp("a\203", "a\003", 2) != 0);
+ static_assert(__builtin_bcmp(0, 0, 0) == 0);
+ static_assert(__builtin_bcmp("abab\0banana", "abab\0banana", 100) == 0); // both-error {{not an integral constant}}\
+ // both-note {{dereferenced one-past-the-end}}
+ static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 100) != 0); // FIXME: Should we reject this?
+ static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0);
+ static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 6) != 0);
+ static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 5) == 0);
}
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/73/builds/10145 Here is the relevant piece of the build log for the reference
|
Check out https://lab.llvm.org/buildbot/#/builders/13/builds/4041:
|
See the discussion in llvm#119678 (comment) and llvm#119544 (comment)
See the discussion in #119678 (comment) and #119544 (comment)
... the same as
__builtin_memcmp
. Also fix a bug we still had when we couldn't find a difference in the two inputs afterSize
bytes.