[clang] f0d6017 - [clang][bytecode] Check memove/memcpy for available elements (#121383)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 31 03:14:31 PST 2024
Author: Timm Baeder
Date: 2024-12-31T12:14:27+01:00
New Revision: f0d60170cc501447c999569db8fe91aacaad5fe2
URL: https://github.com/llvm/llvm-project/commit/f0d60170cc501447c999569db8fe91aacaad5fe2
DIFF: https://github.com/llvm/llvm-project/commit/f0d60170cc501447c999569db8fe91aacaad5fe2.diff
LOG: [clang][bytecode] Check memove/memcpy for available elements (#121383)
Both destination and source pointer need to have at least as many
elements as requested.
Added:
Modified:
clang/lib/AST/ByteCode/InterpBuiltin.cpp
clang/test/AST/ByteCode/builtin-functions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 2ae91feb2d9e8e..d0d8b03deab268 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/SipHash.h"
namespace clang {
@@ -1837,6 +1838,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
assert(Call->getNumArgs() == 3);
unsigned ID = Func->getBuiltinID();
Pointer DestPtr = getParam<Pointer>(Frame, 0);
+ const ASTContext &ASTCtx = S.getASTContext();
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
@@ -1857,34 +1859,55 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
- << DiagPtr.toDiagnosticString(S.getASTContext());
+ << DiagPtr.toDiagnosticString(ASTCtx);
return false;
}
- QualType ElemType;
- if (DestPtr.getFieldDesc()->isArray())
- ElemType = DestPtr.getFieldDesc()->getElemQualType();
- else
- ElemType = DestPtr.getType();
+ QualType DestElemType;
+ size_t RemainingDestElems;
+ if (DestPtr.getFieldDesc()->isArray()) {
+ DestElemType = DestPtr.getFieldDesc()->getElemQualType();
+ RemainingDestElems = (DestPtr.getNumElems() - DestPtr.getIndex());
+ } else {
+ DestElemType = DestPtr.getType();
+ RemainingDestElems = 1;
+ }
+ unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();
- unsigned ElemSize =
- S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
- if (Size.urem(ElemSize) != 0) {
+ if (Size.urem(DestElemSize) != 0) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_memcpy_unsupported)
- << Move << /*IsWchar=*/false << 0 << ElemType << Size << ElemSize;
+ << Move << /*IsWchar=*/false << 0 << DestElemType << Size
+ << DestElemSize;
return false;
}
QualType SrcElemType;
- if (SrcPtr.getFieldDesc()->isArray())
+ size_t RemainingSrcElems;
+ if (SrcPtr.getFieldDesc()->isArray()) {
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
- else
+ RemainingSrcElems = (SrcPtr.getNumElems() - SrcPtr.getIndex());
+ } else {
SrcElemType = SrcPtr.getType();
+ RemainingSrcElems = 1;
+ }
+ unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity();
- if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) {
+ if (!ASTCtx.hasSameUnqualifiedType(DestElemType, SrcElemType)) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun)
- << Move << SrcElemType << ElemType;
+ << Move << SrcElemType << DestElemType;
+ return false;
+ }
+
+ // Check if we have enough elements to read from and write to/
+ size_t RemainingDestBytes = RemainingDestElems * DestElemSize;
+ size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize;
+ if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) {
+ APInt N = Size.udiv(DestElemSize);
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_memcpy_unsupported)
+ << Move << /*IsWChar*/ false << (Size.ugt(RemainingSrcBytes) ? 1 : 2)
+ << DestElemType << toString(N, 10, /*Signed=*/false);
return false;
}
@@ -1905,7 +1928,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
// As a last resort, reject dummy pointers.
if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;
- assert(Size.getZExtValue() % ElemSize == 0);
+ assert(Size.getZExtValue() % DestElemSize == 0);
if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
return false;
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index c1fd1bc1381503..b0f8ea2e55ee0b 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -1244,6 +1244,15 @@ namespace BuiltinMemcpy {
}
static_assert(cpyptr());
+#ifndef __AVR__
+ constexpr int test_memmove(int a, int b, int n) {
+ int arr[4] = {1, 2, 3, 4};
+ __builtin_memmove(arr + a, arr + b, n); // both-note {{destination is not a contiguous array of at least 3 elements of type 'int'}}
+ return result(arr);
+ }
+ static_assert(test_memmove(2, 0, 12) == 4234); // both-error {{constant}} \
+ // both-note {{in call}}
+#endif
}
namespace Memcmp {
More information about the cfe-commits
mailing list