xref: /aosp_15_r20/external/libtextclassifier/native/utils/base/arena_test.cc (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
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