1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker *
4*993b0882SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker *
8*993b0882SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker *
10*993b0882SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker */
16*993b0882SAndroid Build Coastguard Worker
17*993b0882SAndroid Build Coastguard Worker #include "utils/base/arena.h"
18*993b0882SAndroid Build Coastguard Worker
19*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
20*993b0882SAndroid Build Coastguard Worker #include "utils/base/macros.h"
21*993b0882SAndroid Build Coastguard Worker #include "gtest/gtest.h"
22*993b0882SAndroid Build Coastguard Worker
23*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
24*993b0882SAndroid Build Coastguard Worker
25*993b0882SAndroid Build Coastguard Worker //------------------------------------------------------------------------
26*993b0882SAndroid Build Coastguard Worker // Write random data to allocated memory
TestMemory(void * mem,int size)27*993b0882SAndroid Build Coastguard Worker static void TestMemory(void* mem, int size) {
28*993b0882SAndroid Build Coastguard Worker // Do some memory allocation to check that the arena doesn't mess up
29*993b0882SAndroid Build Coastguard Worker // the internal memory allocator
30*993b0882SAndroid Build Coastguard Worker char* tmp[100];
31*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < TC3_ARRAYSIZE(tmp); i++) {
32*993b0882SAndroid Build Coastguard Worker tmp[i] = new char[i * i + 1];
33*993b0882SAndroid Build Coastguard Worker }
34*993b0882SAndroid Build Coastguard Worker
35*993b0882SAndroid Build Coastguard Worker memset(mem, 0xcc, size);
36*993b0882SAndroid Build Coastguard Worker
37*993b0882SAndroid Build Coastguard Worker // Free up the allocated memory;
38*993b0882SAndroid Build Coastguard Worker for (char* s : tmp) {
39*993b0882SAndroid Build Coastguard Worker delete[] s;
40*993b0882SAndroid Build Coastguard Worker }
41*993b0882SAndroid Build Coastguard Worker }
42*993b0882SAndroid Build Coastguard Worker
43*993b0882SAndroid Build Coastguard Worker //------------------------------------------------------------------------
44*993b0882SAndroid Build Coastguard Worker // Check memory ptr
CheckMemory(void * mem,int size)45*993b0882SAndroid Build Coastguard Worker static void CheckMemory(void* mem, int size) {
46*993b0882SAndroid Build Coastguard Worker TC3_CHECK(mem != nullptr);
47*993b0882SAndroid Build Coastguard Worker TestMemory(mem, size);
48*993b0882SAndroid Build Coastguard Worker }
49*993b0882SAndroid Build Coastguard Worker
50*993b0882SAndroid Build Coastguard Worker //------------------------------------------------------------------------
51*993b0882SAndroid Build Coastguard Worker // Check memory ptr and alignment
CheckAlignment(void * mem,int size,int alignment)52*993b0882SAndroid Build Coastguard Worker static void CheckAlignment(void* mem, int size, int alignment) {
53*993b0882SAndroid Build Coastguard Worker TC3_CHECK(mem != nullptr);
54*993b0882SAndroid Build Coastguard Worker ASSERT_EQ(0, (reinterpret_cast<uintptr_t>(mem) & (alignment - 1)))
55*993b0882SAndroid Build Coastguard Worker << "mem=" << mem << " alignment=" << alignment;
56*993b0882SAndroid Build Coastguard Worker TestMemory(mem, size);
57*993b0882SAndroid Build Coastguard Worker }
58*993b0882SAndroid Build Coastguard Worker
59*993b0882SAndroid Build Coastguard Worker //------------------------------------------------------------------------
60*993b0882SAndroid Build Coastguard Worker template <class A>
TestArena(const char * name,A * a,int blksize)61*993b0882SAndroid Build Coastguard Worker void TestArena(const char* name, A* a, int blksize) {
62*993b0882SAndroid Build Coastguard Worker TC3_VLOG(INFO) << "Testing arena '" << name << "': blksize = " << blksize
63*993b0882SAndroid Build Coastguard Worker << ": actual blksize = " << a->block_size();
64*993b0882SAndroid Build Coastguard Worker
65*993b0882SAndroid Build Coastguard Worker int s;
66*993b0882SAndroid Build Coastguard Worker blksize = a->block_size();
67*993b0882SAndroid Build Coastguard Worker
68*993b0882SAndroid Build Coastguard Worker // Allocate zero bytes
69*993b0882SAndroid Build Coastguard Worker TC3_CHECK(a->is_empty());
70*993b0882SAndroid Build Coastguard Worker a->Alloc(0);
71*993b0882SAndroid Build Coastguard Worker TC3_CHECK(a->is_empty());
72*993b0882SAndroid Build Coastguard Worker
73*993b0882SAndroid Build Coastguard Worker // Allocate same as blksize
74*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(blksize), blksize);
75*993b0882SAndroid Build Coastguard Worker TC3_CHECK(!a->is_empty());
76*993b0882SAndroid Build Coastguard Worker
77*993b0882SAndroid Build Coastguard Worker // Allocate some chunks adding up to blksize
78*993b0882SAndroid Build Coastguard Worker s = blksize / 4;
79*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(s), s);
80*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(s), s);
81*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(s), s);
82*993b0882SAndroid Build Coastguard Worker
83*993b0882SAndroid Build Coastguard Worker int s2 = blksize - (s * 3);
84*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(s2), s2);
85*993b0882SAndroid Build Coastguard Worker
86*993b0882SAndroid Build Coastguard Worker // Allocate large chunk
87*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(blksize * 2), blksize * 2);
88*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(blksize * 2 + 1), blksize * 2 + 1);
89*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(blksize * 2 + 2), blksize * 2 + 2);
90*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(blksize * 2 + 3), blksize * 2 + 3);
91*993b0882SAndroid Build Coastguard Worker
92*993b0882SAndroid Build Coastguard Worker // Allocate aligned
93*993b0882SAndroid Build Coastguard Worker s = blksize / 2;
94*993b0882SAndroid Build Coastguard Worker CheckAlignment(a->AllocAligned(s, 1), s, 1);
95*993b0882SAndroid Build Coastguard Worker CheckAlignment(a->AllocAligned(s + 1, 2), s + 1, 2);
96*993b0882SAndroid Build Coastguard Worker CheckAlignment(a->AllocAligned(s + 2, 2), s + 2, 2);
97*993b0882SAndroid Build Coastguard Worker CheckAlignment(a->AllocAligned(s + 3, 4), s + 3, 4);
98*993b0882SAndroid Build Coastguard Worker CheckAlignment(a->AllocAligned(s + 4, 4), s + 4, 4);
99*993b0882SAndroid Build Coastguard Worker CheckAlignment(a->AllocAligned(s + 5, 4), s + 5, 4);
100*993b0882SAndroid Build Coastguard Worker CheckAlignment(a->AllocAligned(s + 6, 4), s + 6, 4);
101*993b0882SAndroid Build Coastguard Worker
102*993b0882SAndroid Build Coastguard Worker // Free
103*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < 100; i++) {
104*993b0882SAndroid Build Coastguard Worker int i2 = i * i;
105*993b0882SAndroid Build Coastguard Worker a->Free(a->Alloc(i2), i2);
106*993b0882SAndroid Build Coastguard Worker }
107*993b0882SAndroid Build Coastguard Worker
108*993b0882SAndroid Build Coastguard Worker // Memdup
109*993b0882SAndroid Build Coastguard Worker char mem[500];
110*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < 500; i++) mem[i] = i & 255;
111*993b0882SAndroid Build Coastguard Worker char* mem2 = a->Memdup(mem, sizeof(mem));
112*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, memcmp(mem, mem2, sizeof(mem)));
113*993b0882SAndroid Build Coastguard Worker
114*993b0882SAndroid Build Coastguard Worker // MemdupPlusNUL
115*993b0882SAndroid Build Coastguard Worker const char* msg_mpn = "won't use all this length";
116*993b0882SAndroid Build Coastguard Worker char* msg2_mpn = a->MemdupPlusNUL(msg_mpn, 10);
117*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strcmp(msg2_mpn, "won't use "));
118*993b0882SAndroid Build Coastguard Worker a->Free(msg2_mpn, 11);
119*993b0882SAndroid Build Coastguard Worker
120*993b0882SAndroid Build Coastguard Worker // Strdup
121*993b0882SAndroid Build Coastguard Worker const char* msg = "arena unit test is cool...";
122*993b0882SAndroid Build Coastguard Worker char* msg2 = a->Strdup(msg);
123*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strcmp(msg, msg2));
124*993b0882SAndroid Build Coastguard Worker a->Free(msg2, strlen(msg) + 1);
125*993b0882SAndroid Build Coastguard Worker
126*993b0882SAndroid Build Coastguard Worker // Strndup
127*993b0882SAndroid Build Coastguard Worker char* msg3 = a->Strndup(msg, 10);
128*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strncmp(msg3, msg, 10));
129*993b0882SAndroid Build Coastguard Worker a->Free(msg3, 10);
130*993b0882SAndroid Build Coastguard Worker TC3_CHECK(!a->is_empty());
131*993b0882SAndroid Build Coastguard Worker
132*993b0882SAndroid Build Coastguard Worker // Reset
133*993b0882SAndroid Build Coastguard Worker a->Reset();
134*993b0882SAndroid Build Coastguard Worker TC3_CHECK(a->is_empty());
135*993b0882SAndroid Build Coastguard Worker
136*993b0882SAndroid Build Coastguard Worker // Realloc
137*993b0882SAndroid Build Coastguard Worker char* m1 = a->Alloc(blksize / 2);
138*993b0882SAndroid Build Coastguard Worker CheckMemory(m1, blksize / 2);
139*993b0882SAndroid Build Coastguard Worker TC3_CHECK(!a->is_empty());
140*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(blksize / 2), blksize / 2); // Allocate another block
141*993b0882SAndroid Build Coastguard Worker m1 = a->Realloc(m1, blksize / 2, blksize);
142*993b0882SAndroid Build Coastguard Worker CheckMemory(m1, blksize);
143*993b0882SAndroid Build Coastguard Worker m1 = a->Realloc(m1, blksize, 23456);
144*993b0882SAndroid Build Coastguard Worker CheckMemory(m1, 23456);
145*993b0882SAndroid Build Coastguard Worker
146*993b0882SAndroid Build Coastguard Worker // Shrink
147*993b0882SAndroid Build Coastguard Worker m1 = a->Shrink(m1, 200);
148*993b0882SAndroid Build Coastguard Worker CheckMemory(m1, 200);
149*993b0882SAndroid Build Coastguard Worker m1 = a->Shrink(m1, 100);
150*993b0882SAndroid Build Coastguard Worker CheckMemory(m1, 100);
151*993b0882SAndroid Build Coastguard Worker m1 = a->Shrink(m1, 1);
152*993b0882SAndroid Build Coastguard Worker CheckMemory(m1, 1);
153*993b0882SAndroid Build Coastguard Worker a->Free(m1, 1);
154*993b0882SAndroid Build Coastguard Worker TC3_CHECK(!a->is_empty());
155*993b0882SAndroid Build Coastguard Worker
156*993b0882SAndroid Build Coastguard Worker // Calloc
157*993b0882SAndroid Build Coastguard Worker char* m2 = a->Calloc(2000);
158*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < 2000; ++i) {
159*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, m2[i]);
160*993b0882SAndroid Build Coastguard Worker }
161*993b0882SAndroid Build Coastguard Worker
162*993b0882SAndroid Build Coastguard Worker // bytes_until_next_allocation
163*993b0882SAndroid Build Coastguard Worker a->Reset();
164*993b0882SAndroid Build Coastguard Worker TC3_CHECK(a->is_empty());
165*993b0882SAndroid Build Coastguard Worker int alignment = blksize - a->bytes_until_next_allocation();
166*993b0882SAndroid Build Coastguard Worker TC3_VLOG(INFO) << "Alignment overhead in initial block = " << alignment;
167*993b0882SAndroid Build Coastguard Worker
168*993b0882SAndroid Build Coastguard Worker s = a->bytes_until_next_allocation() - 1;
169*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(s), s);
170*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(a->bytes_until_next_allocation(), 1);
171*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(1), 1);
172*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(a->bytes_until_next_allocation(), 0);
173*993b0882SAndroid Build Coastguard Worker
174*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(2 * blksize), 2 * blksize);
175*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(a->bytes_until_next_allocation(), 0);
176*993b0882SAndroid Build Coastguard Worker
177*993b0882SAndroid Build Coastguard Worker CheckMemory(a->Alloc(1), 1);
178*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(a->bytes_until_next_allocation(), blksize - 1);
179*993b0882SAndroid Build Coastguard Worker
180*993b0882SAndroid Build Coastguard Worker s = blksize / 2;
181*993b0882SAndroid Build Coastguard Worker char* m0 = a->Alloc(s);
182*993b0882SAndroid Build Coastguard Worker CheckMemory(m0, s);
183*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(a->bytes_until_next_allocation(), blksize - s - 1);
184*993b0882SAndroid Build Coastguard Worker m0 = a->Shrink(m0, 1);
185*993b0882SAndroid Build Coastguard Worker CheckMemory(m0, 1);
186*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(a->bytes_until_next_allocation(), blksize - 2);
187*993b0882SAndroid Build Coastguard Worker
188*993b0882SAndroid Build Coastguard Worker a->Reset();
189*993b0882SAndroid Build Coastguard Worker TC3_CHECK(a->is_empty());
190*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(a->bytes_until_next_allocation(), blksize - alignment);
191*993b0882SAndroid Build Coastguard Worker }
192*993b0882SAndroid Build Coastguard Worker
EnsureNoAddressInRangeIsPoisoned(void * buffer,size_t range_size)193*993b0882SAndroid Build Coastguard Worker static void EnsureNoAddressInRangeIsPoisoned(void* buffer, size_t range_size) {
194*993b0882SAndroid Build Coastguard Worker #ifdef ADDRESS_SANITIZER
195*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(nullptr, __asan_region_is_poisoned(buffer, range_size));
196*993b0882SAndroid Build Coastguard Worker #endif
197*993b0882SAndroid Build Coastguard Worker }
198*993b0882SAndroid Build Coastguard Worker
DoTest(const char * label,int blksize,char * buffer)199*993b0882SAndroid Build Coastguard Worker static void DoTest(const char* label, int blksize, char* buffer) {
200*993b0882SAndroid Build Coastguard Worker {
201*993b0882SAndroid Build Coastguard Worker UnsafeArena ua(buffer, blksize);
202*993b0882SAndroid Build Coastguard Worker TestArena((std::string("UnsafeArena") + label).c_str(), &ua, blksize);
203*993b0882SAndroid Build Coastguard Worker }
204*993b0882SAndroid Build Coastguard Worker EnsureNoAddressInRangeIsPoisoned(buffer, blksize);
205*993b0882SAndroid Build Coastguard Worker }
206*993b0882SAndroid Build Coastguard Worker
207*993b0882SAndroid Build Coastguard Worker //------------------------------------------------------------------------
208*993b0882SAndroid Build Coastguard Worker class BasicTest : public ::testing::TestWithParam<int> {};
209*993b0882SAndroid Build Coastguard Worker
210*993b0882SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(AllSizes, BasicTest,
211*993b0882SAndroid Build Coastguard Worker ::testing::Values(BaseArena::kDefaultAlignment + 1, 10,
212*993b0882SAndroid Build Coastguard Worker 100, 1024, 12345, 123450, 131072,
213*993b0882SAndroid Build Coastguard Worker 1234500));
214*993b0882SAndroid Build Coastguard Worker
TEST_P(BasicTest,DoTest)215*993b0882SAndroid Build Coastguard Worker TEST_P(BasicTest, DoTest) {
216*993b0882SAndroid Build Coastguard Worker const int blksize = GetParam();
217*993b0882SAndroid Build Coastguard Worker
218*993b0882SAndroid Build Coastguard Worker // Allocate some memory from heap first
219*993b0882SAndroid Build Coastguard Worker char* tmp[100];
220*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < TC3_ARRAYSIZE(tmp); i++) {
221*993b0882SAndroid Build Coastguard Worker tmp[i] = new char[i * i];
222*993b0882SAndroid Build Coastguard Worker }
223*993b0882SAndroid Build Coastguard Worker
224*993b0882SAndroid Build Coastguard Worker // Initial buffer for testing pre-allocated arenas
225*993b0882SAndroid Build Coastguard Worker char* buffer = new char[blksize + BaseArena::kDefaultAlignment];
226*993b0882SAndroid Build Coastguard Worker
227*993b0882SAndroid Build Coastguard Worker DoTest("", blksize, nullptr);
228*993b0882SAndroid Build Coastguard Worker DoTest("(p0)", blksize, buffer + 0);
229*993b0882SAndroid Build Coastguard Worker DoTest("(p1)", blksize, buffer + 1);
230*993b0882SAndroid Build Coastguard Worker DoTest("(p2)", blksize, buffer + 2);
231*993b0882SAndroid Build Coastguard Worker DoTest("(p3)", blksize, buffer + 3);
232*993b0882SAndroid Build Coastguard Worker DoTest("(p4)", blksize, buffer + 4);
233*993b0882SAndroid Build Coastguard Worker DoTest("(p5)", blksize, buffer + 5);
234*993b0882SAndroid Build Coastguard Worker
235*993b0882SAndroid Build Coastguard Worker // Free up the allocated heap memory
236*993b0882SAndroid Build Coastguard Worker for (char* s : tmp) {
237*993b0882SAndroid Build Coastguard Worker delete[] s;
238*993b0882SAndroid Build Coastguard Worker }
239*993b0882SAndroid Build Coastguard Worker
240*993b0882SAndroid Build Coastguard Worker delete[] buffer;
241*993b0882SAndroid Build Coastguard Worker }
242*993b0882SAndroid Build Coastguard Worker
243*993b0882SAndroid Build Coastguard Worker //------------------------------------------------------------------------
244*993b0882SAndroid Build Coastguard Worker // NOTE: these stats will only be accurate in non-debug mode (otherwise
245*993b0882SAndroid Build Coastguard Worker // they'll all be 0). So: if you want accurate timing, run in "normal"
246*993b0882SAndroid Build Coastguard Worker // or "opt" mode. If you want accurate stats, run in "debug" mode.
ShowStatus(const char * const header,const BaseArena::Status & status)247*993b0882SAndroid Build Coastguard Worker void ShowStatus(const char* const header, const BaseArena::Status& status) {
248*993b0882SAndroid Build Coastguard Worker printf("\n--- status: %s\n", header);
249*993b0882SAndroid Build Coastguard Worker printf(" %zu bytes allocated\n", status.bytes_allocated());
250*993b0882SAndroid Build Coastguard Worker }
251*993b0882SAndroid Build Coastguard Worker
252*993b0882SAndroid Build Coastguard Worker // This just tests the arena code proper, without use of allocators of
253*993b0882SAndroid Build Coastguard Worker // gladiators or STL or anything like that
TestArena2(UnsafeArena * const arena)254*993b0882SAndroid Build Coastguard Worker void TestArena2(UnsafeArena* const arena) {
255*993b0882SAndroid Build Coastguard Worker const char sshort[] = "This is a short string";
256*993b0882SAndroid Build Coastguard Worker char slong[3000];
257*993b0882SAndroid Build Coastguard Worker memset(slong, 'a', sizeof(slong));
258*993b0882SAndroid Build Coastguard Worker slong[sizeof(slong) - 1] = '\0';
259*993b0882SAndroid Build Coastguard Worker
260*993b0882SAndroid Build Coastguard Worker char* s1 = arena->Strdup(sshort);
261*993b0882SAndroid Build Coastguard Worker char* s2 = arena->Strdup(slong);
262*993b0882SAndroid Build Coastguard Worker char* s3 = arena->Strndup(sshort, 100);
263*993b0882SAndroid Build Coastguard Worker char* s4 = arena->Strndup(slong, 100);
264*993b0882SAndroid Build Coastguard Worker char* s5 = arena->Memdup(sshort, 10);
265*993b0882SAndroid Build Coastguard Worker char* s6 = arena->Realloc(s5, 10, 20);
266*993b0882SAndroid Build Coastguard Worker arena->Shrink(s5, 10); // get s5 back to using 10 bytes again
267*993b0882SAndroid Build Coastguard Worker char* s7 = arena->Memdup(slong, 10);
268*993b0882SAndroid Build Coastguard Worker char* s8 = arena->Realloc(s7, 10, 5);
269*993b0882SAndroid Build Coastguard Worker char* s9 = arena->Strdup(s1);
270*993b0882SAndroid Build Coastguard Worker char* s10 = arena->Realloc(s4, 100, 10);
271*993b0882SAndroid Build Coastguard Worker char* s11 = arena->Realloc(s4, 10, 100);
272*993b0882SAndroid Build Coastguard Worker char* s12 = arena->Strdup(s9);
273*993b0882SAndroid Build Coastguard Worker char* s13 = arena->Realloc(s9, sizeof(sshort) - 1, 100000); // won't fit :-)
274*993b0882SAndroid Build Coastguard Worker
275*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strcmp(s1, sshort));
276*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strcmp(s2, slong));
277*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strcmp(s3, sshort));
278*993b0882SAndroid Build Coastguard Worker // s4 was realloced so it is not safe to read from
279*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strncmp(s5, sshort, 10));
280*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strncmp(s6, sshort, 10));
281*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(s5, s6); // Should have room to grow here
282*993b0882SAndroid Build Coastguard Worker // only the first 5 bytes of s7 should match; the realloc should have
283*993b0882SAndroid Build Coastguard Worker // caused the next byte to actually go to s9
284*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strncmp(s7, slong, 5));
285*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(s7, s8); // Realloc-smaller should cause us to realloc in place
286*993b0882SAndroid Build Coastguard Worker // s9 was realloced so it is not safe to read from
287*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(s10, s4); // Realloc-smaller should cause us to realloc in place
288*993b0882SAndroid Build Coastguard Worker // Even though we're back to prev size, we had to move the pointer. Thus
289*993b0882SAndroid Build Coastguard Worker // only the first 10 bytes are known since we grew from 10 to 100
290*993b0882SAndroid Build Coastguard Worker TC3_CHECK_NE(s11, s4);
291*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strncmp(s11, slong, 10));
292*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, strcmp(s12, s1));
293*993b0882SAndroid Build Coastguard Worker TC3_CHECK_NE(s12, s13); // too big to grow-in-place, so we should move
294*993b0882SAndroid Build Coastguard Worker }
295*993b0882SAndroid Build Coastguard Worker
296*993b0882SAndroid Build Coastguard Worker //--------------------------------------------------------------------
297*993b0882SAndroid Build Coastguard Worker // Test some fundamental STL containers
298*993b0882SAndroid Build Coastguard Worker
299*993b0882SAndroid Build Coastguard Worker template <typename T>
300*993b0882SAndroid Build Coastguard Worker struct test_hash {
operator ()libtextclassifier3::test_hash301*993b0882SAndroid Build Coastguard Worker int operator()(const T&) const { return 0; }
operator ()libtextclassifier3::test_hash302*993b0882SAndroid Build Coastguard Worker inline bool operator()(const T& s1, const T& s2) const { return s1 < s2; }
303*993b0882SAndroid Build Coastguard Worker };
304*993b0882SAndroid Build Coastguard Worker template <>
305*993b0882SAndroid Build Coastguard Worker struct test_hash<const char*> {
operator ()libtextclassifier3::test_hash306*993b0882SAndroid Build Coastguard Worker int operator()(const char*) const { return 0; }
307*993b0882SAndroid Build Coastguard Worker
operator ()libtextclassifier3::test_hash308*993b0882SAndroid Build Coastguard Worker inline bool operator()(const char* s1, const char* s2) const {
309*993b0882SAndroid Build Coastguard Worker return (s1 != s2) &&
310*993b0882SAndroid Build Coastguard Worker (s2 == nullptr || (s1 != nullptr && strcmp(s1, s2) < 0));
311*993b0882SAndroid Build Coastguard Worker }
312*993b0882SAndroid Build Coastguard Worker };
313*993b0882SAndroid Build Coastguard Worker
314*993b0882SAndroid Build Coastguard Worker // temp definitions from strutil.h, until the compiler error
315*993b0882SAndroid Build Coastguard Worker // generated by #including that file is fixed.
316*993b0882SAndroid Build Coastguard Worker struct streq {
operator ()libtextclassifier3::streq317*993b0882SAndroid Build Coastguard Worker bool operator()(const char* s1, const char* s2) const {
318*993b0882SAndroid Build Coastguard Worker return ((s1 == nullptr && s2 == nullptr) ||
319*993b0882SAndroid Build Coastguard Worker (s1 && s2 && *s1 == *s2 && strcmp(s1, s2) == 0));
320*993b0882SAndroid Build Coastguard Worker }
321*993b0882SAndroid Build Coastguard Worker };
322*993b0882SAndroid Build Coastguard Worker struct strlt {
operator ()libtextclassifier3::strlt323*993b0882SAndroid Build Coastguard Worker bool operator()(const char* s1, const char* s2) const {
324*993b0882SAndroid Build Coastguard Worker return (s1 != s2) &&
325*993b0882SAndroid Build Coastguard Worker (s2 == nullptr || (s1 != nullptr && strcmp(s1, s2) < 0));
326*993b0882SAndroid Build Coastguard Worker }
327*993b0882SAndroid Build Coastguard Worker };
328*993b0882SAndroid Build Coastguard Worker
DoPoisonTest(BaseArena * b,size_t size)329*993b0882SAndroid Build Coastguard Worker void DoPoisonTest(BaseArena* b, size_t size) {
330*993b0882SAndroid Build Coastguard Worker #ifdef ADDRESS_SANITIZER
331*993b0882SAndroid Build Coastguard Worker TC3_LOG(INFO) << "DoPoisonTest(" << b << ", " << size << ")";
332*993b0882SAndroid Build Coastguard Worker char* c1 = b->SlowAlloc(size);
333*993b0882SAndroid Build Coastguard Worker char* c2 = b->SlowAlloc(size);
334*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(nullptr, __asan_region_is_poisoned(c1, size));
335*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(nullptr, __asan_region_is_poisoned(c2, size));
336*993b0882SAndroid Build Coastguard Worker char* c3 = b->SlowRealloc(c2, size, size / 2);
337*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(nullptr, __asan_region_is_poisoned(c3, size / 2));
338*993b0882SAndroid Build Coastguard Worker TC3_CHECK_NE(nullptr, __asan_region_is_poisoned(c2, size));
339*993b0882SAndroid Build Coastguard Worker b->Reset();
340*993b0882SAndroid Build Coastguard Worker TC3_CHECK_NE(nullptr, __asan_region_is_poisoned(c1, size));
341*993b0882SAndroid Build Coastguard Worker TC3_CHECK_NE(nullptr, __asan_region_is_poisoned(c2, size));
342*993b0882SAndroid Build Coastguard Worker TC3_CHECK_NE(nullptr, __asan_region_is_poisoned(c3, size / 2));
343*993b0882SAndroid Build Coastguard Worker #endif
344*993b0882SAndroid Build Coastguard Worker }
345*993b0882SAndroid Build Coastguard Worker
TEST(ArenaTest,TestPoison)346*993b0882SAndroid Build Coastguard Worker TEST(ArenaTest, TestPoison) {
347*993b0882SAndroid Build Coastguard Worker {
348*993b0882SAndroid Build Coastguard Worker UnsafeArena arena(512);
349*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 128);
350*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 256);
351*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 512);
352*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 1024);
353*993b0882SAndroid Build Coastguard Worker }
354*993b0882SAndroid Build Coastguard Worker
355*993b0882SAndroid Build Coastguard Worker char* buffer = new char[512];
356*993b0882SAndroid Build Coastguard Worker {
357*993b0882SAndroid Build Coastguard Worker UnsafeArena arena(buffer, 512);
358*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 128);
359*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 256);
360*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 512);
361*993b0882SAndroid Build Coastguard Worker DoPoisonTest(&arena, 1024);
362*993b0882SAndroid Build Coastguard Worker }
363*993b0882SAndroid Build Coastguard Worker EnsureNoAddressInRangeIsPoisoned(buffer, 512);
364*993b0882SAndroid Build Coastguard Worker
365*993b0882SAndroid Build Coastguard Worker delete[] buffer;
366*993b0882SAndroid Build Coastguard Worker }
367*993b0882SAndroid Build Coastguard Worker
368*993b0882SAndroid Build Coastguard Worker //------------------------------------------------------------------------
369*993b0882SAndroid Build Coastguard Worker
370*993b0882SAndroid Build Coastguard Worker template <class A>
TestStrndupUnterminated()371*993b0882SAndroid Build Coastguard Worker void TestStrndupUnterminated() {
372*993b0882SAndroid Build Coastguard Worker const char kFoo[3] = {'f', 'o', 'o'};
373*993b0882SAndroid Build Coastguard Worker char* source = new char[3];
374*993b0882SAndroid Build Coastguard Worker memcpy(source, kFoo, sizeof(kFoo));
375*993b0882SAndroid Build Coastguard Worker A arena(4096);
376*993b0882SAndroid Build Coastguard Worker char* dup = arena.Strndup(source, sizeof(kFoo));
377*993b0882SAndroid Build Coastguard Worker TC3_CHECK_EQ(0, memcmp(dup, kFoo, sizeof(kFoo)));
378*993b0882SAndroid Build Coastguard Worker delete[] source;
379*993b0882SAndroid Build Coastguard Worker }
380*993b0882SAndroid Build Coastguard Worker
TEST(ArenaTest,StrndupWithUnterminatedStringUnsafe)381*993b0882SAndroid Build Coastguard Worker TEST(ArenaTest, StrndupWithUnterminatedStringUnsafe) {
382*993b0882SAndroid Build Coastguard Worker TestStrndupUnterminated<UnsafeArena>();
383*993b0882SAndroid Build Coastguard Worker }
384*993b0882SAndroid Build Coastguard Worker
385*993b0882SAndroid Build Coastguard Worker } // namespace libtextclassifier3
386