Skip to content

Commit adba24a

Browse files
authored
[clang][bytecode] Add missing __builtin_memcpy checks (#135975)
Add a test for type punning and tests and the necessary checks for non-trivially-copyable types and incomplete types.
1 parent d647d66 commit adba24a

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1872,7 +1872,23 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18721872
return false;
18731873
}
18741874

1875-
// Check if we have enough elements to read from and write to/
1875+
if (DestElemType->isIncompleteType() ||
1876+
DestPtr.getType()->isIncompleteType()) {
1877+
QualType DiagType =
1878+
DestElemType->isIncompleteType() ? DestElemType : DestPtr.getType();
1879+
S.FFDiag(S.Current->getSource(OpPC),
1880+
diag::note_constexpr_memcpy_incomplete_type)
1881+
<< Move << DiagType;
1882+
return false;
1883+
}
1884+
1885+
if (!DestElemType.isTriviallyCopyableType(ASTCtx)) {
1886+
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_nontrivial)
1887+
<< Move << DestElemType;
1888+
return false;
1889+
}
1890+
1891+
// Check if we have enough elements to read from and write to.
18761892
size_t RemainingDestBytes = RemainingDestElems * DestElemSize;
18771893
size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize;
18781894
if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) {

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,30 @@ extern "C" {
3333
extern wchar_t *wmemcpy(wchar_t *d, const wchar_t *s, size_t n);
3434
}
3535

36+
37+
constexpr int test_address_of_incomplete_array_type() { // both-error {{never produces a constant expression}}
38+
extern int arr[];
39+
__builtin_memmove(&arr, &arr, 4 * sizeof(arr[0])); // both-note 2{{cannot constant evaluate 'memmove' between objects of incomplete type 'int[]'}}
40+
return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
41+
}
42+
static_assert(test_address_of_incomplete_array_type() == 1234, ""); // both-error {{constant}} \
43+
// both-note {{in call}}
44+
45+
46+
struct NonTrivial {
47+
constexpr NonTrivial() : n(0) {}
48+
constexpr NonTrivial(const NonTrivial &) : n(1) {}
49+
int n;
50+
};
51+
constexpr bool test_nontrivial_memcpy() { // ref-error {{never produces a constant}}
52+
NonTrivial arr[3] = {};
53+
__builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // both-note {{non-trivially-copyable}} \
54+
// ref-note {{non-trivially-copyable}}
55+
return true;
56+
}
57+
static_assert(test_nontrivial_memcpy()); // both-error {{constant}} \
58+
// both-note {{in call}}
59+
3660
namespace strcmp {
3761
constexpr char kFoobar[6] = {'f','o','o','b','a','r'};
3862
constexpr char kFoobazfoobar[12] = {'f','o','o','b','a','z','f','o','o','b','a','r'};
@@ -1349,6 +1373,17 @@ namespace BuiltinMemcpy {
13491373
// both-note {{source of 'memcpy' is (void *)123}}
13501374
static_assert(__builtin_memcpy(fold(reinterpret_cast<wchar_t*>(123)), &global, sizeof(wchar_t))); // both-error {{not an integral constant expression}} \
13511375
// both-note {{destination of 'memcpy' is (void *)123}}
1376+
1377+
1378+
constexpr float type_pun(const unsigned &n) {
1379+
float f = 0.0f;
1380+
__builtin_memcpy(&f, &n, 4); // both-note {{cannot constant evaluate 'memcpy' from object of type 'const unsigned int' to object of type 'float'}}
1381+
return f;
1382+
}
1383+
static_assert(type_pun(0x3f800000) == 1.0f); // both-error {{constant}} \
1384+
// both-note {{in call}}
1385+
1386+
13521387
}
13531388

13541389
namespace Memcmp {

0 commit comments

Comments
 (0)