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.
23extern "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
39const 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.
69void *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
82char *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
91char *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
100void 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
107bool 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
125bool 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
161bool 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
230bool 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
304bool 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
361bool 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
399bool 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
485bool 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
553bool 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
630bool 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
771bool 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
861int 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