Skip to content

Commit cf6a520

Browse files
authored
[clang][bytecode] Fix builtin_memcmp buffer sizes for pointers (#130570)
Don't use the pointer size, but the number of elements multiplied by the element size.
1 parent 8a8f135 commit cf6a520

File tree

2 files changed

+126
-4
lines changed

2 files changed

+126
-4
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,10 +1892,12 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
18921892
};
18931893

18941894
const ASTContext &ASTCtx = S.getASTContext();
1895+
QualType ElemTypeA = getElemType(PtrA);
1896+
QualType ElemTypeB = getElemType(PtrB);
18951897
// FIXME: This is an arbitrary limitation the current constant interpreter
18961898
// had. We could remove this.
1897-
if (!IsWide && (!isOneByteCharacterType(getElemType(PtrA)) ||
1898-
!isOneByteCharacterType(getElemType(PtrB)))) {
1899+
if (!IsWide && (!isOneByteCharacterType(ElemTypeA) ||
1900+
!isOneByteCharacterType(ElemTypeB))) {
18991901
S.FFDiag(S.Current->getSource(OpPC),
19001902
diag::note_constexpr_memcmp_unsupported)
19011903
<< ASTCtx.BuiltinInfo.getQuotedName(ID) << PtrA.getType()
@@ -1908,15 +1910,15 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
19081910

19091911
// Now, read both pointers to a buffer and compare those.
19101912
BitcastBuffer BufferA(
1911-
Bits(ASTCtx.getTypeSize(PtrA.getFieldDesc()->getType())));
1913+
Bits(ASTCtx.getTypeSize(ElemTypeA) * PtrA.getNumElems()));
19121914
readPointerToBuffer(S.getContext(), PtrA, BufferA, false);
19131915
// FIXME: The swapping here is UNDOING something we do when reading the
19141916
// data into the buffer.
19151917
if (ASTCtx.getTargetInfo().isBigEndian())
19161918
swapBytes(BufferA.Data.get(), BufferA.byteSize().getQuantity());
19171919

19181920
BitcastBuffer BufferB(
1919-
Bits(ASTCtx.getTypeSize(PtrB.getFieldDesc()->getType())));
1921+
Bits(ASTCtx.getTypeSize(ElemTypeB) * PtrB.getNumElems()));
19201922
readPointerToBuffer(S.getContext(), PtrB, BufferB, false);
19211923
// FIXME: The swapping here is UNDOING something we do when reading the
19221924
// data into the buffer.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// RUN: %clang_cc1 -std=c++2c -fexperimental-new-constant-interpreter -verify=expected,both %s
2+
// RUN: %clang_cc1 -std=c++2c -verify=ref,both %s
3+
4+
// both-no-diagnostics
5+
6+
namespace std {
7+
inline namespace {
8+
template <int __v> struct integral_constant {
9+
static const int value = __v;
10+
};
11+
template <bool, class> using __enable_if_t = int;
12+
char *addressof(char &);
13+
struct pointer_traits {
14+
template <class _Up> using rebind = _Up *;
15+
};
16+
} // namespace
17+
} // namespace std
18+
void *operator new(decltype(sizeof(int)), void *);
19+
namespace std {
20+
inline namespace {
21+
template <class _Tp> using __make_unsigned_t = __make_unsigned(_Tp);
22+
template <class _Default, template <class> class>
23+
using __detected_or_t = _Default;
24+
template <class _Tp> using __pointer_member = _Tp;
25+
template <class _Tp, class>
26+
using __pointer = __detected_or_t<_Tp *, __pointer_member>;
27+
template <class _Tp> using __size_type_member = _Tp;
28+
template <class, class _DiffType>
29+
using __size_type =
30+
__detected_or_t<__make_unsigned_t<_DiffType>, __size_type_member>;
31+
struct allocation_result {
32+
char *ptr;
33+
unsigned long count;
34+
};
35+
template <class _Alloc> struct allocator_traits {
36+
using allocator_type = _Alloc;
37+
using pointer =
38+
__pointer<typename allocator_type::value_type, allocator_type>;
39+
using const_pointer = pointer_traits::rebind<char>;
40+
using size_type =
41+
__size_type<allocator_type, decltype(static_cast<int *>(nullptr) -
42+
static_cast<int *>(nullptr))>;
43+
template <class _Ap>
44+
static constexpr allocation_result allocate_at_least(_Ap __alloc,
45+
size_type __n) {
46+
return {__alloc.allocate(__n), (unsigned long)__n};
47+
}
48+
};
49+
template <class _Alloc>
50+
constexpr auto __allocate_at_least(_Alloc __alloc, decltype(sizeof(int)) __n) {
51+
return allocator_traits<_Alloc>::allocate_at_least(__alloc, __n);
52+
}
53+
template <class> struct allocator {
54+
typedef char value_type;
55+
constexpr char *allocate(decltype(sizeof(int)) __n) {
56+
return static_cast<char *>(operator new(__n));
57+
}
58+
constexpr void deallocate(char *__p) { operator delete(__p); }
59+
};
60+
struct __long {
61+
allocator_traits<allocator<char>>::size_type __is_long_;
62+
allocator_traits<allocator<char>>::size_type __size_;
63+
allocator_traits<allocator<char>>::pointer __data_;
64+
};
65+
allocator<char> __alloc_;
66+
struct basic_string {
67+
__long __l;
68+
constexpr basic_string(basic_string &__str) {
69+
allocator_traits<allocator<char>>::size_type __trans_tmp_1 =
70+
__str.__get_long_size();
71+
auto __allocation = __allocate_at_least(__alloc_, __trans_tmp_1);
72+
for (allocator_traits<allocator<char>>::size_type __i = 0;
73+
__i != __allocation.count; ++__i) {
74+
char *__trans_tmp_9 = addressof(__allocation.ptr[__i]);
75+
new (__trans_tmp_9) char();
76+
}
77+
__l.__data_ = __allocation.ptr;
78+
__l.__is_long_ = __l.__size_ = __trans_tmp_1;
79+
}
80+
template <__enable_if_t<integral_constant<false>::value, int> = 0>
81+
constexpr basic_string(const char *__s, allocator<char>) {
82+
decltype(sizeof(int)) __trans_tmp_11, __i = 0;
83+
for (; __s[__i]; ++__i)
84+
__trans_tmp_11 = __i;
85+
auto __allocation = __allocate_at_least(__alloc_, 1);
86+
__l.__data_ = __allocation.ptr;
87+
__l.__size_ = __trans_tmp_11;
88+
}
89+
constexpr ~basic_string() {
90+
allocator<char> __a;
91+
__a.deallocate(__l.__data_);
92+
}
93+
constexpr allocator_traits<allocator<char>>::size_type size() {
94+
return __l.__is_long_;
95+
}
96+
constexpr char *data() {
97+
allocator_traits<allocator<char>>::const_pointer __trans_tmp_6 =
98+
__l.__is_long_ ? __l.__data_ : 0;
99+
return __trans_tmp_6;
100+
}
101+
constexpr allocator_traits<allocator<char>>::size_type __get_long_size() {
102+
return __l.__size_;
103+
}
104+
};
105+
constexpr void operator==(basic_string __lhs, basic_string __rhs) {
106+
decltype(sizeof(int)) __lhs_sz = __lhs.size();
107+
char *__trans_tmp_10 = __rhs.data(), *__trans_tmp_15 = __lhs.data();
108+
__builtin_memcmp(__trans_tmp_15, __trans_tmp_10, __lhs_sz);
109+
}
110+
} // namespace
111+
} // namespace std
112+
constexpr void test(std::basic_string s0) {
113+
std::basic_string s1 = s0, s2(s0);
114+
s2 == s1;
115+
}
116+
constexpr bool test() {
117+
test(std::basic_string("2345678901234567890", std::allocator<char>()));
118+
return true;
119+
}
120+
static_assert(test());

0 commit comments

Comments
 (0)