• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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