Skip to content

Commit f0d6017

Browse files
authored
[clang][bytecode] Check memove/memcpy for available elements (#121383)
Both destination and source pointer need to have at least as many elements as requested.
1 parent b35d345 commit f0d6017

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/Basic/Builtins.h"
1818
#include "clang/Basic/TargetBuiltins.h"
1919
#include "clang/Basic/TargetInfo.h"
20+
#include "llvm/ADT/StringExtras.h"
2021
#include "llvm/Support/SipHash.h"
2122

2223
namespace clang {
@@ -1837,6 +1838,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18371838
assert(Call->getNumArgs() == 3);
18381839
unsigned ID = Func->getBuiltinID();
18391840
Pointer DestPtr = getParam<Pointer>(Frame, 0);
1841+
const ASTContext &ASTCtx = S.getASTContext();
18401842
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
18411843
const APSInt &Size =
18421844
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
@@ -1857,34 +1859,55 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18571859
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
18581860
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
18591861
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
1860-
<< DiagPtr.toDiagnosticString(S.getASTContext());
1862+
<< DiagPtr.toDiagnosticString(ASTCtx);
18611863
return false;
18621864
}
18631865

1864-
QualType ElemType;
1865-
if (DestPtr.getFieldDesc()->isArray())
1866-
ElemType = DestPtr.getFieldDesc()->getElemQualType();
1867-
else
1868-
ElemType = DestPtr.getType();
1866+
QualType DestElemType;
1867+
size_t RemainingDestElems;
1868+
if (DestPtr.getFieldDesc()->isArray()) {
1869+
DestElemType = DestPtr.getFieldDesc()->getElemQualType();
1870+
RemainingDestElems = (DestPtr.getNumElems() - DestPtr.getIndex());
1871+
} else {
1872+
DestElemType = DestPtr.getType();
1873+
RemainingDestElems = 1;
1874+
}
1875+
unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();
18691876

1870-
unsigned ElemSize =
1871-
S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
1872-
if (Size.urem(ElemSize) != 0) {
1877+
if (Size.urem(DestElemSize) != 0) {
18731878
S.FFDiag(S.Current->getSource(OpPC),
18741879
diag::note_constexpr_memcpy_unsupported)
1875-
<< Move << /*IsWchar=*/false << 0 << ElemType << Size << ElemSize;
1880+
<< Move << /*IsWchar=*/false << 0 << DestElemType << Size
1881+
<< DestElemSize;
18761882
return false;
18771883
}
18781884

18791885
QualType SrcElemType;
1880-
if (SrcPtr.getFieldDesc()->isArray())
1886+
size_t RemainingSrcElems;
1887+
if (SrcPtr.getFieldDesc()->isArray()) {
18811888
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
1882-
else
1889+
RemainingSrcElems = (SrcPtr.getNumElems() - SrcPtr.getIndex());
1890+
} else {
18831891
SrcElemType = SrcPtr.getType();
1892+
RemainingSrcElems = 1;
1893+
}
1894+
unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity();
18841895

1885-
if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) {
1896+
if (!ASTCtx.hasSameUnqualifiedType(DestElemType, SrcElemType)) {
18861897
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun)
1887-
<< Move << SrcElemType << ElemType;
1898+
<< Move << SrcElemType << DestElemType;
1899+
return false;
1900+
}
1901+
1902+
// Check if we have enough elements to read from and write to/
1903+
size_t RemainingDestBytes = RemainingDestElems * DestElemSize;
1904+
size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize;
1905+
if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) {
1906+
APInt N = Size.udiv(DestElemSize);
1907+
S.FFDiag(S.Current->getSource(OpPC),
1908+
diag::note_constexpr_memcpy_unsupported)
1909+
<< Move << /*IsWChar*/ false << (Size.ugt(RemainingSrcBytes) ? 1 : 2)
1910+
<< DestElemType << toString(N, 10, /*Signed=*/false);
18881911
return false;
18891912
}
18901913

@@ -1905,7 +1928,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
19051928
// As a last resort, reject dummy pointers.
19061929
if (DestPtr.isDummy() || SrcPtr.isDummy())
19071930
return false;
1908-
assert(Size.getZExtValue() % ElemSize == 0);
1931+
assert(Size.getZExtValue() % DestElemSize == 0);
19091932
if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
19101933
return false;
19111934

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,15 @@ namespace BuiltinMemcpy {
12441244
}
12451245
static_assert(cpyptr());
12461246

1247+
#ifndef __AVR__
1248+
constexpr int test_memmove(int a, int b, int n) {
1249+
int arr[4] = {1, 2, 3, 4};
1250+
__builtin_memmove(arr + a, arr + b, n); // both-note {{destination is not a contiguous array of at least 3 elements of type 'int'}}
1251+
return result(arr);
1252+
}
1253+
static_assert(test_memmove(2, 0, 12) == 4234); // both-error {{constant}} \
1254+
// both-note {{in call}}
1255+
#endif
12471256
}
12481257

12491258
namespace Memcmp {

0 commit comments

Comments
 (0)