1 /*
2 ** Copyright 2013 The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/mman.h>
21
22 // Put any local test functions into the extern below.
23 extern "C" {
24 }
25
26 #define FENCEPOST_LENGTH 8
27
28 #define MAX_MEMCPY_TEST_SIZE 2048
29 #define MAX_MEMCPY_BUFFER_SIZE (3 * MAX_MEMCPY_TEST_SIZE)
30
31 #define MAX_MEMSET_TEST_SIZE 2048
32 #define MAX_MEMSET_BUFFER_SIZE (3 * MAX_MEMSET_TEST_SIZE)
33
34 #define MAX_STRING_TEST_SIZE 1024
35 #define MAX_STRING_BUFFER_SIZE (3 * MAX_STRING_TEST_SIZE)
36
37 #define MAX_STRCAT_DST_SIZE 32
38
39 const int kStringAligns[][4] = {
40 // All zeroes to use the values returned from malloc.
41 { 0, 0, 0, 0 },
42
43 { 1, 0, 1, 0 },
44 { 2, 0, 2, 0 },
45 { 4, 0, 4, 0 },
46 { 8, 0, 8, 0 },
47
48 { 8, 0, 4, 0 },
49 { 4, 0, 8, 0 },
50
51 { 8, 0, 8, 1 },
52 { 8, 0, 8, 2 },
53 { 8, 0, 8, 3 },
54 { 8, 1, 8, 0 },
55 { 8, 2, 8, 0 },
56 { 8, 3, 8, 0 },
57
58 { 4, 0, 4, 1 },
59 { 4, 0, 4, 2 },
60 { 4, 0, 4, 3 },
61 { 4, 1, 4, 0 },
62 { 4, 2, 4, 0 },
63 { 4, 3, 4, 0 },
64 };
65
66 #define STRING_ALIGN_LEN (sizeof(kStringAligns)/sizeof(int[4]))
67
68 // Return a pointer into the current string with the specified alignment.
getAlignedPtr(void * orig_ptr,int alignment,int or_mask)69 void *getAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
70 uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
71 if (alignment > 0) {
72 // When setting the alignment, set it to exactly the alignment chosen.
73 // The pointer returned will be guaranteed not to be aligned to anything
74 // more than that.
75 ptr += alignment - (ptr & (alignment - 1));
76 ptr |= alignment | or_mask;
77 }
78
79 return reinterpret_cast<void*>(ptr);
80 }
81
setString(char * str,size_t size)82 char *setString(char *str, size_t size) {
83 for (size_t i = 0; i < size; i++) {
84 str[i] = (char)(32 + (i % 96));
85 }
86 str[size] = '\0';
87
88 return str;
89 }
90
allocateString()91 char *allocateString() {
92 char *str = reinterpret_cast<char*>(malloc(MAX_STRING_BUFFER_SIZE+1));
93 if (!str) {
94 return NULL;
95 }
96
97 return setString(str, MAX_STRING_BUFFER_SIZE);
98 }
99
setFencepost(uint8_t * buffer)100 void setFencepost(uint8_t *buffer) {
101 for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
102 buffer[i] = 0xde;
103 buffer[i+1] = 0xad;
104 }
105 }
106
verifyFencepost(uint8_t * buffer)107 bool verifyFencepost(uint8_t *buffer) {
108 for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
109 if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
110 uint8_t expected_value;
111 if (buffer[i] == 0xde) {
112 i++;
113 expected_value = 0xad;
114 } else {
115 expected_value = 0xde;
116 }
117 printf(" mismatch at fencepost[%d], expected %d found %d\n",
118 i, expected_value, buffer[i]);
119 return false;
120 }
121 }
122 return true;
123 }
124
doStrcmpExpectEqual(char * string1,char * string2,const int align[4],int (* test_strcmp)(const char * s1,const char * s2),bool verbose)125 bool doStrcmpExpectEqual(char *string1, char *string2, const int align[4],
126 int (*test_strcmp)(const char *s1, const char *s2),
127 bool verbose) {
128 char *align_str1 = (char*)getAlignedPtr(string1, align[0], align[1]);
129 char *align_str2 = (char*)getAlignedPtr(string2, align[2], align[3]);
130
131 for (size_t i = 0; i < MAX_STRING_TEST_SIZE; i++) {
132 for (size_t j = 0; j < i; j++) {
133 align_str1[j] = (char)(32 + (j % 96));
134 align_str2[j] = align_str1[j];
135 }
136 align_str1[i] = '\0';
137 align_str2[i] = '\0';
138
139 // Set the characters after the string terminates to different values
140 // to verify that the strcmp is not over checking.
141 for (size_t j = i+1; j < i+64; j++) {
142 align_str1[j] = (char)(32 + j);
143 align_str2[j] = (char)(40 + j);
144 }
145
146 if (verbose) {
147 printf("Testing size %d, align_str1=%p[%d,%d], align_str2=%p[%d,%d]\n",
148 i, align_str1, align[0], align[1], align_str2, align[2], align[3]);
149 }
150
151 if (test_strcmp(align_str1, align_str2) != 0) {
152 printf(" Failed at size %d, src1 %p, src2 %p\n",
153 i, align_str1, align_str2);
154 return false;
155 }
156 }
157
158 return true;
159 }
160
doStrcmpExpectDiff(char * string1,char * string2,const int diff_align[2],const int align[4],char diff_char,int (* test_strcmp)(const char * s1,const char * s2),bool verbose)161 bool doStrcmpExpectDiff(char *string1, char *string2, const int diff_align[2],
162 const int align[4], char diff_char,
163 int (*test_strcmp)(const char *s1, const char *s2),
164 bool verbose) {
165 char *align_str1 = (char*)getAlignedPtr(string1, align[0], align[1]);
166 char *align_str2 = (char*)getAlignedPtr(string2, align[2], align[3]);
167
168 for (int i = 0; i < MAX_STRING_TEST_SIZE; i++) {
169 // Use valid ascii characters, no unprintables characters.
170 align_str1[i] = (char)(32 + (i % 96));
171 if (align_str1[i] == diff_char) {
172 // Assumes that one less than the diff character is still a valid
173 // character.
174 align_str1[i] = diff_char-1;
175 }
176 align_str2[i] = align_str1[i];
177 }
178 align_str1[MAX_STRING_TEST_SIZE] = '\0';
179 align_str2[MAX_STRING_TEST_SIZE] = '\0';
180
181 // Quick check to make sure that the strcmp knows that everything is
182 // equal. If it's so broken that it already thinks the strings are
183 // different, then there is no point running any of the other tests.
184 if (test_strcmp(align_str1, align_str2) != 0) {
185 printf(" strcmp is too broken to do difference testing.\n");
186 return false;
187 }
188
189 // Get a pointer into the string at the specified alignment.
190 char *bad = (char*)getAlignedPtr(align_str1+MAX_STRING_TEST_SIZE/2,
191 diff_align[0], diff_align[1]);
192
193 char saved_char = bad[0];
194 bad[0] = diff_char;
195
196 if (verbose) {
197 printf("Testing difference, align_str1=%p[%d,%d], align_str2=%p[%d,%d]\n",
198 align_str1, align[0], align[1], align_str2, align[2], align[3]);
199 }
200 if (test_strcmp(align_str1, align_str2) == 0) {
201 printf(" Did not miscompare at size %d, src1 %p, src2 %p, diff %p\n",
202 MAX_STRING_TEST_SIZE, align_str1, align_str2, bad);
203 return false;
204 }
205 bad[0] = saved_char;
206
207 // Re-verify that something hasn't gone horribly wrong.
208 if (test_strcmp(align_str1, align_str2) != 0) {
209 printf(" strcmp is too broken to do difference testing.\n");
210 return false;
211 }
212
213 bad = (char*)getAlignedPtr(align_str2+MAX_STRING_TEST_SIZE/2, diff_align[0],
214 diff_align[1]);
215 bad[0] = diff_char;
216
217 if (verbose) {
218 printf("Testing reverse difference, align_str1=%p[%d,%d], align_str2=%p[%d,%d]\n",
219 align_str1, align[0], align[1], align_str2, align[2], align[3]);
220 }
221 if (test_strcmp(align_str1, align_str2) == 0) {
222 printf(" Did not miscompare at size %d, src1 %p, src2 %p, diff %p\n",
223 MAX_STRING_TEST_SIZE, align_str1, align_str2, bad);
224 return false;
225 }
226
227 return true;
228 }
229
doStrcmpCheckRead(int (* test_strcmp)(const char * s1,const char * s2),bool verbose)230 bool doStrcmpCheckRead(int (*test_strcmp)(const char *s1, const char *s2),
231 bool verbose) {
232 // In order to verify that the strcmp is not reading past the end of the
233 // string, create some strings that end near unreadable memory.
234 long pagesize = sysconf(_SC_PAGE_SIZE);
235 char *memory = (char*)memalign(pagesize, 2 * pagesize);
236 if (memory == NULL) {
237 perror("Unable to allocate memory.\n");
238 return false;
239 }
240
241 // Make the second page unreadable and unwritable.
242 if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
243 perror("Unable to set protection of page.\n");
244 return false;
245 }
246
247 size_t max_size = pagesize < MAX_STRING_TEST_SIZE ? pagesize-1 : MAX_STRING_TEST_SIZE;
248 // Allocate an extra byte beyond the string terminator to allow us to
249 // extend the string to be larger than our protected string.
250 char *other_string = (char *)malloc(max_size+2);
251 if (other_string == NULL) {
252 perror("Unable to allocate memory.\n");
253 return false;
254 }
255 char *string;
256 for (size_t i = 0; i <= max_size; i++) {
257 string = &memory[pagesize-i-1];
258 for (size_t j = 0; j < i; j++) {
259 other_string[j] = (char)(32 + (j % 96));
260 string[j] = other_string[j];
261 }
262 other_string[i] = '\0';
263 string[i] = '\0';
264
265 if (verbose) {
266 printf("Testing size %d, strings equal.\n", i);
267 }
268 if (test_strcmp(other_string, string) != 0) {
269 printf(" Failed at size %d, src1 %p, src2 %p\n", i, other_string, string);
270 return false;
271 }
272
273 if (verbose) {
274 printf("Testing size %d, strings equal reverse strings.\n", i);
275 }
276 if (test_strcmp(string, other_string) != 0) {
277 printf(" Failed at size %d, src1 %p, src2 %p\n", i, string, other_string);
278 return false;
279 }
280
281 // Now make other_string longer than our protected string.
282 other_string[i] = '1';
283 other_string[i+1] = '\0';
284
285 if (verbose) {
286 printf("Testing size %d, strings not equal.\n", i);
287 }
288 if (test_strcmp(other_string, string) == 0) {
289 printf(" Failed at size %d, src1 %p, src2 %p\n", i, other_string, string);
290 return false;
291 }
292
293 if (verbose) {
294 printf("Testing size %d, strings not equal reverse the strings.\n", i);
295 }
296 if (test_strcmp(string, other_string) == 0) {
297 printf(" Failed at size %d, src1 %p, src2 %p\n", i, string, other_string);
298 return false;
299 }
300 }
301 return true;
302 }
303
runStrcmpTest(int (* test_strcmp)(const char * s1,const char * s2),bool verbose)304 bool runStrcmpTest(int (*test_strcmp)(const char *s1, const char *s2),
305 bool verbose) {
306 char *string1 = allocateString();
307 char *string2 = allocateString();
308 if (string1 == NULL || string2 == NULL) {
309 perror("Unable to allocate memory.\n");
310 return false;
311 }
312
313 printf(" Verifying equal sized strings at different alignments.\n");
314 for (size_t i = 0; i < STRING_ALIGN_LEN; i++) {
315 if (!doStrcmpExpectEqual(string1, string2, kStringAligns[i], test_strcmp,
316 verbose)) {
317 return false;
318 }
319 }
320
321 // Test the function finds strings with differences at specific locations.
322 const int diff_aligns[][2] = {
323 { 4, 0 },
324 { 4, 1 },
325 { 4, 2 },
326 { 4, 3 },
327 { 8, 0 },
328 { 8, 1 },
329 { 8, 2 },
330 { 8, 3 },
331 };
332 printf(" Verifying different strings at different alignments.\n");
333 for (size_t i = 0; i < sizeof(diff_aligns)/sizeof(int[2]); i++) {
334 // First loop put the string terminator at the chosen alignment.
335 for (size_t j = 0; j < STRING_ALIGN_LEN; j++) {
336 if (!doStrcmpExpectDiff(string1, string2, diff_aligns[i],
337 kStringAligns[j], '\0', test_strcmp, verbose)) {
338 return false;
339 }
340 }
341 // Second loop put a different character at the chosen alignment.
342 // This character is guaranteed not to be in the original string.
343 for (size_t j = 0; j < STRING_ALIGN_LEN; j++) {
344 if (!doStrcmpExpectDiff(string1, string2, diff_aligns[i],
345 kStringAligns[j], '\0', test_strcmp, verbose)) {
346 return false;
347 }
348 }
349 }
350
351 printf(" Verifying strcmp does not read too many bytes.\n");
352 if (!doStrcmpCheckRead(test_strcmp, verbose)) {
353 return false;
354 }
355
356 printf(" All tests pass.\n");
357
358 return true;
359 }
360
doStrlenCheck(size_t size,char * string,int align,int or_mask,size_t (* test_strlen)(const char *),bool verbose)361 bool doStrlenCheck(size_t size, char *string, int align, int or_mask,
362 size_t (*test_strlen)(const char *), bool verbose) {
363 char *aligned_string = reinterpret_cast<char*>(getAlignedPtr(string, align, or_mask));
364 size_t len;
365 if (verbose) {
366 printf("Testing size %d, align=%p[%d,%d]\n", size, aligned_string, align, or_mask);
367 }
368
369 aligned_string[size] = '\0';
370 len = test_strlen(aligned_string);
371 if (len != size) {
372 printf("Failed at size %d, length returned %u, align=%p[%d,%d]\n",
373 size, len, aligned_string, align, or_mask);
374 return false;
375 }
376
377 if (verbose) {
378 printf("Testing size %d with extra zeros after string, align=%p[%d,%d]\n",
379 size, aligned_string, align, or_mask);
380 }
381
382 for (size_t j = size+1; j <= size+16; j++) {
383 aligned_string[j] = '\0';
384 }
385
386 len = test_strlen(aligned_string);
387 if (len != size) {
388 printf("Failed at size %d, length returned %u with zeroes after string, align=%p[%d,%d]\n",
389 size, len, aligned_string, align, or_mask);
390 return false;
391 }
392
393 for (size_t j = size; j <= size+16; j++) {
394 aligned_string[j] = (char)(32 + (j % 96));
395 }
396 return true;
397 }
398
runStrlenTest(size_t (* test_strlen)(const char *),bool verbose)399 bool runStrlenTest(size_t (*test_strlen)(const char *),
400 bool verbose) {
401 char *string = allocateString();
402 if (string == NULL) {
403 perror("Unable to allocate memory.\n");
404 return false;
405 }
406
407 // Check different string alignments. All zeroes indicates that the
408 // unmodified malloc values should be used.
409 const int aligns[][2] = {
410 // All zeroes to use the values returned from malloc.
411 { 0, 0 },
412
413 { 1, 0 },
414 { 2, 0 },
415 { 4, 0 },
416 { 8, 0 },
417 { 16, 0 },
418 { 32, 0 },
419
420 { 8, 1 },
421 { 8, 2 },
422 { 8, 3 },
423
424 { 4, 1 },
425 { 4, 2 },
426 { 4, 3 },
427 };
428
429 printf(" Verifying string lengths at different alignments.\n");
430 for (size_t i = 0; i < sizeof(aligns)/sizeof(int[2]); i++) {
431 for (size_t j = 0; j <= MAX_STRING_TEST_SIZE; j++) {
432 if (!doStrlenCheck(j, string, aligns[i][0], aligns[i][1], test_strlen, verbose)) {
433 return false;
434 }
435 }
436 }
437
438 printf(" Verifying strlen does not read past end of string.\n");
439
440 // In order to verify that strlen is not reading past the end of the
441 // string, create strings that end near unreadable memory.
442 long pagesize = sysconf(_SC_PAGE_SIZE);
443 char *memory = (char*)memalign(pagesize, 2 * pagesize);
444 if (memory == NULL) {
445 perror("Unable to allocate memory.\n");
446 return false;
447 }
448
449 // Make the second page unreadable and unwritable.
450 if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
451 perror("Unable to set protection of page.\n");
452 return false;
453 }
454
455 size_t max_size = pagesize < MAX_STRING_TEST_SIZE ? pagesize-1 : MAX_STRING_TEST_SIZE;
456 for (long i = 0; i < pagesize; i++) {
457 memory[i] = (char)(32 + (i % 96));
458 }
459
460 size_t len;
461 for (size_t i = 0; i < sizeof(aligns)/sizeof(int[2]); i++) {
462 for (size_t j = 0; j <= max_size; j++) {
463 string = &memory[pagesize-j-1];
464 string[j] = '\0';
465
466 if (verbose) {
467 printf("Testing size %d overread, align=%p[%d,%d]\n",
468 j, string, aligns[i][0], aligns[i][1]);
469 }
470 len = test_strlen(string);
471 if (len != j) {
472 printf(" Failed at size %u, returned %u, align=%p[%d,%d]\n",
473 j, len, string, aligns[i][0], aligns[i][1]);
474 return false;
475 }
476 string[j] = (char)(32 + (j % 96));
477 }
478 }
479
480 printf(" All tests pass.\n");
481
482 return true;
483 }
484
runStrcpyTest(char * (* test_strcpy)(char *,const char *),bool verbose)485 bool runStrcpyTest(char *(*test_strcpy)(char *, const char *),
486 bool verbose) {
487 char *src = allocateString();
488 if (src == NULL) {
489 perror("Unable to allocate memory.\n");
490 return false;
491 }
492 char *dst = allocateString();
493 if (dst == NULL) {
494 perror("Unable to allocate memory.\n");
495 return false;
496 }
497
498 printf(" Verifying string lengths at different alignments.\n");
499 char *src_align;
500 char *dst_align;
501 char *dst_ret;
502 for (size_t i = 0; i < STRING_ALIGN_LEN; i++) {
503 for (size_t copy_len = 0; copy_len <= MAX_STRING_TEST_SIZE; copy_len++) {
504 if (kStringAligns[i][0]) {
505 src_align = reinterpret_cast<char*>(getAlignedPtr(src+FENCEPOST_LENGTH, kStringAligns[i][0], kStringAligns[i][1]));
506 dst_align = reinterpret_cast<char*>(getAlignedPtr(dst+FENCEPOST_LENGTH, kStringAligns[i][2], kStringAligns[i][3]));
507 } else {
508 src_align = src;
509 dst_align = dst;
510 }
511 setString(src_align, copy_len);
512 memset(dst_align, 0, copy_len+1);
513
514 if (dst_align != dst) {
515 setFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]));
516 }
517 setFencepost(reinterpret_cast<uint8_t*>(&dst_align[copy_len+1]));
518
519 if (verbose) {
520 printf("Testing copy_len %u, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
521 copy_len, src_align, kStringAligns[i][0], kStringAligns[i][1],
522 dst_align, kStringAligns[i][2], kStringAligns[i][3]);
523 }
524
525 dst_ret = test_strcpy(dst_align, src_align);
526 if (dst_ret != dst_align) {
527 printf("copy_len %u returned incorrect value: expected %p, got %p\n",
528 copy_len, dst_align, dst_ret);
529 return false;
530 }
531 if (memcmp(src_align, dst_align, copy_len) != 0) {
532 printf("copy_len %u failed to copy properly: src and dst aren't equal\n", copy_len);
533 return false;
534 }
535
536 if (dst_align != dst && !verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]))) {
537 printf("copy_len %u fencepost before dst was overwritten\n", copy_len);
538 return false;
539 }
540
541 if (!verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[copy_len+1]))) {
542 printf("copy_len %u fencepost at end of dst was overwritten\n", copy_len);
543 return false;
544 }
545 }
546 }
547
548 printf(" All tests pass.\n");
549
550 return true;
551 }
552
runStrcatTest(char * (* test_strcat)(char *,const char *),bool verbose)553 bool runStrcatTest(char *(*test_strcat)(char *, const char *),
554 bool verbose) {
555 char *src = allocateString();
556 if (src == NULL) {
557 perror("Unable to allocate memory.\n");
558 return false;
559 }
560 char *dst = allocateString();
561 if (dst == NULL) {
562 perror("Unable to allocate memory.\n");
563 return false;
564 }
565
566 printf(" Verifying string lengths at different alignments.\n");
567 char *src_align;
568 char *dst_align;
569 char *dst_ret;
570 for (size_t i = 0; i < STRING_ALIGN_LEN; i++) {
571 for (size_t dst_len = 0; dst_len <= MAX_STRCAT_DST_SIZE; dst_len++) {
572 for (size_t copy_len = 0; copy_len <= MAX_STRING_TEST_SIZE; copy_len++) {
573 if (kStringAligns[i][0]) {
574 src_align = reinterpret_cast<char*>(getAlignedPtr(src+FENCEPOST_LENGTH, kStringAligns[i][0], kStringAligns[i][1]));
575 dst_align = reinterpret_cast<char*>(getAlignedPtr(dst+FENCEPOST_LENGTH, kStringAligns[i][2], kStringAligns[i][3]));
576 } else {
577 src_align = src;
578 dst_align = dst;
579 }
580 setString(src_align, copy_len);
581 memset(dst_align, 'd', dst_len);
582 memset(dst_align+dst_len, 0, copy_len+1);
583
584 if (dst_align != dst) {
585 setFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]));
586 }
587 setFencepost(reinterpret_cast<uint8_t*>(&dst_align[copy_len+dst_len+1]));
588
589 if (verbose) {
590 printf("Testing copy_len %u, dst_len %u, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
591 copy_len, dst_len, src_align, kStringAligns[i][0], kStringAligns[i][1],
592 dst_align, kStringAligns[i][2], kStringAligns[i][3]);
593 }
594
595 dst_ret = test_strcat(dst_align, src_align);
596 if (dst_ret != dst_align) {
597 printf("dst_len %u, copy_len %u returned incorrect value: expected %p, got %p\n",
598 dst_len, copy_len, dst_align, dst_ret);
599 return false;
600 }
601 for (size_t j = 0; j < dst_len; j++) {
602 if (dst_align[j] != 'd') {
603 printf("dst_len %u, copy_len %u: strcat overwrote dst string\n",
604 dst_len, copy_len);
605 return false;
606 }
607 }
608 if (memcmp(src_align, dst_align+dst_len, copy_len+1) != 0) {
609 printf("dst_len %u, copy_len %u failed to copy properly: src and dst aren't equal\n",
610 dst_len, copy_len);
611 return false;
612 }
613
614 if (dst_align != dst && !verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]))) {
615 return false;
616 }
617
618 if (!verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[dst_len+copy_len+1]))) {
619 return false;
620 }
621 }
622 }
623 }
624
625 printf(" All tests pass.\n");
626
627 return true;
628 }
629
runMemcpyTest(void * (* test_memcpy)(void * dst,const void * src,size_t n),bool verbose)630 bool runMemcpyTest(void* (*test_memcpy)(void *dst, const void *src, size_t n),
631 bool verbose) {
632 uint8_t *dst = reinterpret_cast<uint8_t*>(malloc(MAX_MEMCPY_BUFFER_SIZE));
633 uint8_t *src = reinterpret_cast<uint8_t*>(malloc(MAX_MEMCPY_BUFFER_SIZE));
634 if (dst == NULL || src == NULL) {
635 perror("Unable to allocate memory.\n");
636 return false;
637 }
638
639 // Set the source to a known pattern once. The assumption is that the
640 // memcpy is not so broken that it will write in to the source buffer.
641 // However, do not write zeroes into the source so a very quick can be
642 // made to verify the source has not been modified.
643 for (int i = 0; i < MAX_MEMCPY_BUFFER_SIZE; i++) {
644 src[i] = i % 256;
645 if (src[i] == 0) {
646 src[i] = 0xaa;
647 }
648 }
649
650 const int aligns[][4] = {
651 // Src and dst use pointers returned by malloc.
652 { 0, 0, 0, 0 },
653
654 // Src and dst at same alignment.
655 { 1, 0, 1, 0 },
656 { 2, 0, 2, 0 },
657 { 4, 0, 4, 0 },
658 { 8, 0, 8, 0 },
659 { 16, 0, 16, 0 },
660 { 32, 0, 32, 0 },
661 { 64, 0, 64, 0 },
662 { 128, 0, 128, 0 },
663
664 // Different alignments between src and dst.
665 { 8, 0, 4, 0 },
666 { 4, 0, 8, 0 },
667 { 16, 0, 4, 0 },
668 { 4, 0, 16, 0 },
669
670 // General unaligned cases.
671 { 4, 0, 4, 1 },
672 { 4, 0, 4, 2 },
673 { 4, 0, 4, 3 },
674 { 4, 1, 4, 0 },
675 { 4, 2, 4, 0 },
676 { 4, 3, 4, 0 },
677
678 // All non-word aligned cases.
679 { 4, 1, 4, 0 },
680 { 4, 1, 4, 1 },
681 { 4, 1, 4, 2 },
682 { 4, 1, 4, 3 },
683
684 { 4, 2, 4, 0 },
685 { 4, 2, 4, 1 },
686 { 4, 2, 4, 2 },
687 { 4, 2, 4, 3 },
688
689 { 4, 3, 4, 0 },
690 { 4, 3, 4, 1 },
691 { 4, 3, 4, 2 },
692 { 4, 3, 4, 3 },
693
694 { 2, 0, 4, 0 },
695 { 4, 0, 2, 0 },
696 { 2, 0, 2, 0 },
697
698 // Invoke the unaligned case where the code needs to align dst to 0x10.
699 { 128, 1, 128, 4 },
700 { 128, 1, 128, 8 },
701 { 128, 1, 128, 12 },
702 { 128, 1, 128, 16 },
703 };
704
705 printf(" Verifying variable sized copies at different alignments.\n");
706 uint8_t *src_align, *dst_align;
707 for (size_t i = 0; i < sizeof(aligns)/sizeof(int[4]); i++) {
708 for (size_t len = 0; len <= MAX_MEMCPY_TEST_SIZE; len++) {
709 if (aligns[i][0]) {
710 src_align = (uint8_t*)getAlignedPtr(src+FENCEPOST_LENGTH, aligns[i][0],
711 aligns[i][1]);
712 dst_align = (uint8_t*)getAlignedPtr(dst+FENCEPOST_LENGTH, aligns[i][2],
713 aligns[i][3]);
714 } else {
715 src_align = src;
716 dst_align = dst;
717 }
718
719 if (verbose) {
720 printf("Testing size %d, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
721 len, src_align, aligns[i][0], aligns[i][1],
722 dst_align, aligns[i][2], aligns[i][3]);
723 }
724
725 memset(dst_align, 0, len);
726
727 // Don't add a pre fencepost if we are using the value from the malloc.
728 if (dst_align != dst) {
729 setFencepost(&dst_align[-8]);
730 }
731 setFencepost(&dst_align[len]);
732
733 test_memcpy(dst_align, src_align, len);
734
735 for (size_t j = 0; j < len; j++) {
736 if (dst_align[j] != src_align[j] || !src_align[j]) {
737 if (!src_align[j]) {
738 printf(" src_align[%d] is 0, memcpy wrote into the source.\n", j);
739 } else {
740 printf(" mismatch at %d, expected %d found %d\n", j,
741 src_align[j], dst_align[j]);
742 }
743 printf(" Failed at size %d, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
744 len, src_align, aligns[i][0], aligns[i][1],
745 dst_align, aligns[i][2], aligns[i][3]);
746 return false;
747 }
748 }
749 if (dst_align != dst && !verifyFencepost(&dst_align[-8])) {
750 printf(" wrote before the array.\n");
751 printf(" Failed at size %d, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
752 len, src_align, aligns[i][0], aligns[i][1],
753 dst_align, aligns[i][2], aligns[i][3]);
754 return false;
755 }
756 if (!verifyFencepost(&dst_align[len])) {
757 printf(" wrote past the end of the array.\n");
758 printf(" Failed at size %d, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
759 len, src_align, aligns[i][0], aligns[i][1],
760 dst_align, aligns[i][2], aligns[i][3]);
761 return false;
762 }
763 }
764 }
765
766 printf(" All tests pass.\n");
767
768 return true;
769 }
770
runMemsetTest(void * (* test_memset)(void * s,int c,size_t n),bool verbose)771 bool runMemsetTest(void* (*test_memset)(void *s, int c, size_t n),
772 bool verbose) {
773 uint8_t *buf = reinterpret_cast<uint8_t*>(malloc(MAX_MEMSET_BUFFER_SIZE));
774 if (buf == NULL) {
775 perror("Unable to allocate memory.\n");
776 return false;
777 }
778
779 const int aligns[][2] = {
780 // Use malloc return values unaltered.
781 { 0, 0 },
782
783 // Different alignments.
784 { 1, 0 },
785 { 2, 0 },
786 { 4, 0 },
787 { 8, 0 },
788 { 16, 0 },
789 { 32, 0 },
790 { 64, 0 },
791
792 // Different alignments between src and dst.
793 { 8, 1 },
794 { 8, 2 },
795 { 8, 3 },
796 { 8, 4 },
797 { 8, 5 },
798 { 8, 6 },
799 { 8, 7 },
800 };
801
802 printf(" Verifying variable sized memsets at different alignments.\n");
803 uint8_t *buf_align;
804 for (size_t i = 0; i < sizeof(aligns)/sizeof(int[2]); i++) {
805 for (size_t len = 0; len <= MAX_MEMSET_TEST_SIZE; len++) {
806 if (aligns[i]) {
807 buf_align = (uint8_t*)getAlignedPtr(buf+FENCEPOST_LENGTH, aligns[i][0],
808 aligns[i][1]);
809 } else {
810 buf_align = buf;
811 }
812
813 if (verbose) {
814 printf("Testing size %d, buf_align=%p[%d,%d]\n",
815 len, buf_align, aligns[i][0], aligns[i][1]);
816 }
817
818 // Set the buffer to all zero without memset since it might be the
819 // function we are testing.
820 for (size_t j = 0; j < len; j++) {
821 buf_align[j] = 0;
822 }
823
824 // Don't add a pre fencepost if we are using the value from the malloc.
825 if (buf_align != buf) {
826 setFencepost(&buf_align[-8]);
827 }
828 setFencepost(&buf_align[len]);
829
830 int value = (len % 255) + 1;
831 test_memset(buf_align, value, len);
832
833 for (size_t j = 0; j < len; j++) {
834 if (buf_align[j] != value) {
835 printf(" Failed at size %d[%d,%d!=%d], buf_align=%p[%d,%d]\n",
836 len, j, buf_align[j], value, buf_align, aligns[i][0],
837 aligns[i][1]);
838 return false;
839 }
840 }
841 if (buf_align != buf && !verifyFencepost(&buf_align[-8])) {
842 printf(" wrote before the beginning of the array.\n");
843 printf(" Failed at size %d, buf_align=%p[%d,%d]\n",
844 len, buf_align, aligns[i][0], aligns[i][1]);
845 return false;
846 }
847 if (!verifyFencepost(&buf_align[len])) {
848 printf(" wrote after the end of the array.\n");
849 printf(" Failed at size %d, buf_align=%p[%d,%d]\n",
850 len, buf_align, aligns[i][0], aligns[i][1]);
851 return false;
852 }
853 }
854 }
855
856 printf(" All tests pass.\n");
857
858 return true;
859 }
860
main(int argc,char ** argv)861 int main(int argc, char **argv) {
862 bool verbose = false;
863 if (argc == 2 && strcmp(argv[1], "-v") == 0) {
864 verbose = true;
865 }
866
867 bool tests_passing = true;
868
869 printf("Testing strcmp...\n");
870 tests_passing = runStrcmpTest(strcmp, verbose) && tests_passing;
871
872 printf("Testing memcpy...\n");
873 tests_passing = runMemcpyTest(memcpy, verbose) && tests_passing;
874
875 printf("Testing memset...\n");
876 tests_passing = runMemsetTest(memset, verbose) && tests_passing;
877
878 printf("Testing strlen...\n");
879 tests_passing = runStrlenTest(strlen, verbose) && tests_passing;
880
881 printf("Testing strcpy...\n");
882 tests_passing = runStrcpyTest(strcpy, verbose) && tests_passing;
883
884 printf("Testing strcat...\n");
885 tests_passing = runStrcatTest(strcat, verbose) && tests_passing;
886
887 return (tests_passing ? 0 : 1);
888 }
889