Commits

Anonymous committed d8f4bfc Merge

Merge "Add tests for strcpy and strcat."

Comments (0)

Files changed (1)

libc_test/main.cpp

 #define MAX_MEMSET_TEST_SIZE      2048
 #define MAX_MEMSET_BUFFER_SIZE    (3 * MAX_MEMSET_TEST_SIZE)
 
-#define MAX_STRCMP_TEST_SIZE      1024
-#define MAX_STRCMP_BUFFER_SIZE    (3 * MAX_STRCMP_TEST_SIZE)
+#define MAX_STRING_TEST_SIZE      1024
+#define MAX_STRING_BUFFER_SIZE    (3 * MAX_STRING_TEST_SIZE)
 
-#define MAX_STRLEN_TEST_SIZE      1024
-#define MAX_STRLEN_BUFFER_SIZE    (3 * MAX_STRLEN_TEST_SIZE)
+#define MAX_STRCAT_DST_SIZE       32
+
+const int kStringAligns[][4] = {
+  // All zeroes to use the values returned from malloc.
+  { 0, 0, 0, 0 },
+
+  { 1, 0, 1, 0 },
+  { 2, 0, 2, 0 },
+  { 4, 0, 4, 0 },
+  { 8, 0, 8, 0 },
+
+  { 8, 0, 4, 0 },
+  { 4, 0, 8, 0 },
+
+  { 8, 0, 8, 1 },
+  { 8, 0, 8, 2 },
+  { 8, 0, 8, 3 },
+  { 8, 1, 8, 0 },
+  { 8, 2, 8, 0 },
+  { 8, 3, 8, 0 },
+
+  { 4, 0, 4, 1 },
+  { 4, 0, 4, 2 },
+  { 4, 0, 4, 3 },
+  { 4, 1, 4, 0 },
+  { 4, 2, 4, 0 },
+  { 4, 3, 4, 0 },
+};
+
+#define STRING_ALIGN_LEN  (sizeof(kStringAligns)/sizeof(int[4]))
 
 // Return a pointer into the current string with the specified alignment.
 void *getAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
   return reinterpret_cast<void*>(ptr);
 }
 
+char *setString(char *str, size_t size) {
+  for (size_t i = 0; i < size; i++) {
+    str[i] = (char)(32 + (i % 96));
+  }
+  str[size] = '\0';
+
+  return str;
+}
+
+char *allocateString() {
+  char *str = reinterpret_cast<char*>(malloc(MAX_STRING_BUFFER_SIZE+1));
+  if (!str) {
+    return NULL;
+  }
+
+  return setString(str, MAX_STRING_BUFFER_SIZE);
+}
+
 void setFencepost(uint8_t *buffer) {
   for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
     buffer[i] = 0xde;
       } else {
         expected_value = 0xde;
       }
-      printf("   mismatch at fencepost[%d], expected %d found %d\n",
+      printf("    mismatch at fencepost[%d], expected %d found %d\n",
              i, expected_value, buffer[i]);
       return false;
     }
   return true;
 }
 
-bool doStrcmpExpectEqual(char *string1, char *string2, int align[4],
+bool doStrcmpExpectEqual(char *string1, char *string2, const int align[4],
                          int (*test_strcmp)(const char *s1, const char *s2),
                          bool verbose) {
   char *align_str1 = (char*)getAlignedPtr(string1, align[0], align[1]);
   char *align_str2 = (char*)getAlignedPtr(string2, align[2], align[3]);
 
-  for (size_t i = 0; i < MAX_STRCMP_TEST_SIZE; i++) {
+  for (size_t i = 0; i < MAX_STRING_TEST_SIZE; i++) {
     for (size_t j = 0; j < i; j++) {
       align_str1[j] = (char)(32 + (j % 96));
       align_str2[j] = align_str1[j];
   return true;
 }
 
-bool doStrcmpExpectDiff(char *string1, char *string2, int diff_align[2],
-                        int align[4], char diff_char,
+bool 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) {
   char *align_str1 = (char*)getAlignedPtr(string1, align[0], align[1]);
   char *align_str2 = (char*)getAlignedPtr(string2, align[2], align[3]);
 
-  for (int i = 0; i < MAX_STRCMP_TEST_SIZE; i++) {
+  for (int i = 0; i < MAX_STRING_TEST_SIZE; i++) {
     // Use valid ascii characters, no unprintables characters.
     align_str1[i] = (char)(32 + (i % 96));
     if (align_str1[i] == diff_char) {
     }
     align_str2[i] = align_str1[i];
   }
-  align_str1[MAX_STRCMP_TEST_SIZE] = '\0';
-  align_str2[MAX_STRCMP_TEST_SIZE] = '\0';
+  align_str1[MAX_STRING_TEST_SIZE] = '\0';
+  align_str2[MAX_STRING_TEST_SIZE] = '\0';
 
   // Quick check to make sure that the strcmp knows that everything is
   // equal. If it's so broken that it already thinks the strings are
   }
 
   // Get a pointer into the string at the specified alignment.
-  char *bad = (char*)getAlignedPtr(align_str1+MAX_STRCMP_TEST_SIZE/2,
+  char *bad = (char*)getAlignedPtr(align_str1+MAX_STRING_TEST_SIZE/2,
                                    diff_align[0], diff_align[1]);
 
   char saved_char = bad[0];
   }
   if (test_strcmp(align_str1, align_str2) == 0) {
     printf("   Did not miscompare at size %d, src1 %p, src2 %p, diff %p\n",
-           MAX_STRCMP_TEST_SIZE, align_str1, align_str2, bad);
+           MAX_STRING_TEST_SIZE, align_str1, align_str2, bad);
     return false;
   }
   bad[0] = saved_char;
     return false;
   }
 
-  bad = (char*)getAlignedPtr(align_str2+MAX_STRCMP_TEST_SIZE/2, diff_align[0],
+  bad = (char*)getAlignedPtr(align_str2+MAX_STRING_TEST_SIZE/2, diff_align[0],
                              diff_align[1]);
   bad[0] = diff_char;
 
   }
   if (test_strcmp(align_str1, align_str2) == 0) {
     printf("    Did not miscompare at size %d, src1 %p, src2 %p, diff %p\n",
-           MAX_STRCMP_TEST_SIZE, align_str1, align_str2, bad);
+           MAX_STRING_TEST_SIZE, align_str1, align_str2, bad);
     return false;
   }
 
     return false;
   }
 
-  size_t max_size = pagesize < MAX_STRCMP_TEST_SIZE ? pagesize-1 : MAX_STRCMP_TEST_SIZE;
+  size_t max_size = pagesize < MAX_STRING_TEST_SIZE ? pagesize-1 : MAX_STRING_TEST_SIZE;
   // Allocate an extra byte beyond the string terminator to allow us to
   // extend the string to be larger than our protected string.
   char *other_string = (char *)malloc(max_size+2);
 
 bool runStrcmpTest(int (*test_strcmp)(const char *s1, const char *s2),
                    bool verbose) {
-  // Allocate two large buffers to hold the two strings.
-  char *string1 = reinterpret_cast<char*>(malloc(MAX_STRCMP_BUFFER_SIZE+1));
-  char *string2 = reinterpret_cast<char*>(malloc(MAX_STRCMP_BUFFER_SIZE+1));
+  char *string1 = allocateString();
+  char *string2 = allocateString();
   if (string1 == NULL || string2 == NULL) {
     perror("Unable to allocate memory.\n");
     return false;
   }
 
-  // Initialize the strings to be exactly the same.
-  for (int i = 0; i < MAX_STRCMP_BUFFER_SIZE; i++) {
-    string1[i] = (char)(32 + (i % 96));
-    string2[i] = string1[i];
-  }
-  string1[MAX_STRCMP_BUFFER_SIZE] = '\0';
-  string2[MAX_STRCMP_BUFFER_SIZE] = '\0';
-
-  // Check different string alignments. All zeroes indicates that the
-  // unmodified malloc values should be used.
-  int string_aligns[][4] = {
-    // All zeroes to use the values returned from malloc.
-    { 0, 0, 0, 0 },
-
-    { 1, 0, 1, 0 },
-    { 2, 0, 2, 0 },
-    { 4, 0, 4, 0 },
-    { 8, 0, 8, 0 },
-
-    { 8, 0, 4, 0 },
-    { 4, 0, 8, 0 },
-
-    { 8, 0, 8, 1 },
-    { 8, 0, 8, 2 },
-    { 8, 0, 8, 3 },
-    { 8, 1, 8, 0 },
-    { 8, 2, 8, 0 },
-    { 8, 3, 8, 0 },
-
-    { 4, 0, 4, 1 },
-    { 4, 0, 4, 2 },
-    { 4, 0, 4, 3 },
-    { 4, 1, 4, 0 },
-    { 4, 2, 4, 0 },
-    { 4, 3, 4, 0 },
-  };
-
   printf("  Verifying equal sized strings at different alignments.\n");
-  for (size_t i = 0; i < sizeof(string_aligns)/sizeof(int[4]); i++) {
-    if (!doStrcmpExpectEqual(string1, string2, string_aligns[i], test_strcmp,
+  for (size_t i = 0; i < STRING_ALIGN_LEN; i++) {
+    if (!doStrcmpExpectEqual(string1, string2, kStringAligns[i], test_strcmp,
                              verbose)) {
       return false;
     }
   }
 
   // Test the function finds strings with differences at specific locations.
-  int diff_aligns[][2] = {
+  const int diff_aligns[][2] = {
     { 4, 0 },
     { 4, 1 },
     { 4, 2 },
   printf("  Verifying different strings at different alignments.\n");
   for (size_t i = 0; i < sizeof(diff_aligns)/sizeof(int[2]); i++) {
     // First loop put the string terminator at the chosen alignment.
-    for (size_t j = 0; j < sizeof(string_aligns)/sizeof(int[4]); j++) {
+    for (size_t j = 0; j < STRING_ALIGN_LEN; j++) {
       if (!doStrcmpExpectDiff(string1, string2, diff_aligns[i],
-                              string_aligns[j], '\0', test_strcmp, verbose)) {
+                              kStringAligns[j], '\0', test_strcmp, verbose)) {
         return false;
       }
     }
     // Second loop put a different character at the chosen alignment.
     // This character is guaranteed not to be in the original string.
-    for (size_t j = 0; j < sizeof(string_aligns)/sizeof(int[4]); j++) {
+    for (size_t j = 0; j < STRING_ALIGN_LEN; j++) {
       if (!doStrcmpExpectDiff(string1, string2, diff_aligns[i],
-                              string_aligns[j], '\0', test_strcmp, verbose)) {
+                              kStringAligns[j], '\0', test_strcmp, verbose)) {
         return false;
       }
     }
 
 bool runStrlenTest(size_t (*test_strlen)(const char *),
                    bool verbose) {
-  // Allocate two large buffers to hold the two strings.
-  char *string = reinterpret_cast<char*>(malloc(MAX_STRLEN_BUFFER_SIZE+1));
+  char *string = allocateString();
   if (string == NULL) {
     perror("Unable to allocate memory.\n");
     return false;
   }
 
-  // Initialize the strings to be exactly the same.
-  for (int i = 0; i < MAX_STRLEN_BUFFER_SIZE; i++) {
-    string[i] = (char)(32 + (i % 96));
-  }
-  string[MAX_STRLEN_BUFFER_SIZE] = '\0';
-
   // Check different string alignments. All zeroes indicates that the
   // unmodified malloc values should be used.
-  int aligns[][2] = {
+  const int aligns[][2] = {
     // All zeroes to use the values returned from malloc.
     { 0, 0 },
 
 
   printf("  Verifying string lengths at different alignments.\n");
   for (size_t i = 0; i < sizeof(aligns)/sizeof(int[2]); i++) {
-    for (size_t j = 0; j <= MAX_STRLEN_TEST_SIZE; j++) {
+    for (size_t j = 0; j <= MAX_STRING_TEST_SIZE; j++) {
       if (!doStrlenCheck(j, string, aligns[i][0], aligns[i][1], test_strlen, verbose)) {
         return false;
       }
     return false;
   }
 
-  size_t max_size = pagesize < MAX_STRLEN_TEST_SIZE ? pagesize-1 : MAX_STRLEN_TEST_SIZE;
+  size_t max_size = pagesize < MAX_STRING_TEST_SIZE ? pagesize-1 : MAX_STRING_TEST_SIZE;
   for (long i = 0; i < pagesize; i++) {
     memory[i] = (char)(32 + (i % 96));
   }
   return true;
 }
 
+bool runStrcpyTest(char *(*test_strcpy)(char *, const char *),
+                   bool verbose) {
+  char *src = allocateString();
+  if (src == NULL) {
+    perror("Unable to allocate memory.\n");
+    return false;
+  }
+  char *dst = allocateString();
+  if (dst == NULL) {
+    perror("Unable to allocate memory.\n");
+    return false;
+  }
+
+  printf("  Verifying string lengths at different alignments.\n");
+  char *src_align;
+  char *dst_align;
+  char *dst_ret;
+  for (size_t i = 0; i < STRING_ALIGN_LEN; i++) {
+    for (size_t copy_len = 0; copy_len <= MAX_STRING_TEST_SIZE; copy_len++) {
+      if (kStringAligns[i][0]) {
+        src_align = reinterpret_cast<char*>(getAlignedPtr(src+FENCEPOST_LENGTH, kStringAligns[i][0], kStringAligns[i][1]));
+        dst_align = reinterpret_cast<char*>(getAlignedPtr(dst+FENCEPOST_LENGTH, kStringAligns[i][2], kStringAligns[i][3]));
+      } else {
+        src_align = src;
+        dst_align = dst;
+      }
+      setString(src_align, copy_len);
+      memset(dst_align, 0, copy_len+1);
+
+      if (dst_align != dst) {
+        setFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]));
+      }
+      setFencepost(reinterpret_cast<uint8_t*>(&dst_align[copy_len+1]));
+
+      if (verbose) {
+        printf("Testing copy_len %u, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
+               copy_len, src_align, kStringAligns[i][0], kStringAligns[i][1],
+               dst_align, kStringAligns[i][2], kStringAligns[i][3]);
+      }
+
+      dst_ret = test_strcpy(dst_align, src_align);
+      if (dst_ret != dst_align) {
+        printf("copy_len %u returned incorrect value: expected %p, got %p\n",
+               copy_len, dst_align, dst_ret);
+        return false;
+      }
+      if (memcmp(src_align, dst_align, copy_len) != 0) {
+        printf("copy_len %u failed to copy properly: src and dst aren't equal\n", copy_len);
+        return false;
+      }
+
+      if (dst_align != dst && !verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]))) {
+        printf("copy_len %u fencepost before dst was overwritten\n", copy_len);
+        return false;
+      }
+
+      if (!verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[copy_len+1]))) {
+        printf("copy_len %u fencepost at end of dst was overwritten\n", copy_len);
+        return false;
+      }
+    }
+  }
+
+  printf("  All tests pass.\n");
+
+  return true;
+}
+
+bool runStrcatTest(char *(*test_strcat)(char *, const char *),
+                   bool verbose) {
+  char *src = allocateString();
+  if (src == NULL) {
+    perror("Unable to allocate memory.\n");
+    return false;
+  }
+  char *dst = allocateString();
+  if (dst == NULL) {
+    perror("Unable to allocate memory.\n");
+    return false;
+  }
+
+  printf("  Verifying string lengths at different alignments.\n");
+  char *src_align;
+  char *dst_align;
+  char *dst_ret;
+  for (size_t i = 0; i < STRING_ALIGN_LEN; i++) {
+    for (size_t dst_len = 0; dst_len <= MAX_STRCAT_DST_SIZE; dst_len++) {
+      for (size_t copy_len = 0; copy_len <= MAX_STRING_TEST_SIZE; copy_len++) {
+        if (kStringAligns[i][0]) {
+          src_align = reinterpret_cast<char*>(getAlignedPtr(src+FENCEPOST_LENGTH, kStringAligns[i][0], kStringAligns[i][1]));
+          dst_align = reinterpret_cast<char*>(getAlignedPtr(dst+FENCEPOST_LENGTH, kStringAligns[i][2], kStringAligns[i][3]));
+        } else {
+          src_align = src;
+          dst_align = dst;
+        }
+        setString(src_align, copy_len);
+        memset(dst_align, 'd', dst_len);
+        memset(dst_align+dst_len, 0, copy_len+1);
+
+        if (dst_align != dst) {
+          setFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]));
+        }
+        setFencepost(reinterpret_cast<uint8_t*>(&dst_align[copy_len+dst_len+1]));
+
+        if (verbose) {
+          printf("Testing copy_len %u, dst_len %u, src_align=%p[%d,%d], dst_align=%p[%d,%d]\n",
+                 copy_len, dst_len, src_align, kStringAligns[i][0], kStringAligns[i][1],
+                 dst_align, kStringAligns[i][2], kStringAligns[i][3]);
+        }
+
+        dst_ret = test_strcat(dst_align, src_align);
+        if (dst_ret != dst_align) {
+          printf("dst_len %u, copy_len %u returned incorrect value: expected %p, got %p\n",
+                dst_len, copy_len, dst_align, dst_ret);
+          return false;
+        }
+        for (size_t j = 0; j < dst_len; j++) {
+          if (dst_align[j] != 'd') {
+            printf("dst_len %u, copy_len %u: strcat overwrote dst string\n",
+                   dst_len, copy_len);
+            return false;
+          }
+        }
+        if (memcmp(src_align, dst_align+dst_len, copy_len+1) != 0) {
+          printf("dst_len %u, copy_len %u failed to copy properly: src and dst aren't equal\n",
+                 dst_len, copy_len);
+          return false;
+        }
+
+        if (dst_align != dst && !verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[-FENCEPOST_LENGTH]))) {
+          return false;
+        }
+
+        if (!verifyFencepost(reinterpret_cast<uint8_t*>(&dst_align[dst_len+copy_len+1]))) {
+          return false;
+        }
+      }
+    }
+  }
+
+  printf("  All tests pass.\n");
+
+  return true;
+}
+
 bool runMemcpyTest(void* (*test_memcpy)(void *dst, const void *src, size_t n),
                    bool verbose) {
-  // Allocate two large buffers to hold the dst and src.
   uint8_t *dst = reinterpret_cast<uint8_t*>(malloc(MAX_MEMCPY_BUFFER_SIZE));
   uint8_t *src = reinterpret_cast<uint8_t*>(malloc(MAX_MEMCPY_BUFFER_SIZE));
   if (dst == NULL || src == NULL) {
     }
   }
 
-  int aligns[][4] = {
+  const int aligns[][4] = {
     // Src and dst use pointers returned by malloc.
     { 0, 0, 0, 0 },
 
 
 bool runMemsetTest(void* (*test_memset)(void *s, int c, size_t n),
                    bool verbose) {
-  // Allocate one large buffer to hold the dst.
   uint8_t *buf = reinterpret_cast<uint8_t*>(malloc(MAX_MEMSET_BUFFER_SIZE));
   if (buf == NULL) {
     perror("Unable to allocate memory.\n");
     return false;
   }
 
-  int aligns[][2] = {
+  const int aligns[][2] = {
     // Use malloc return values unaltered.
     { 0, 0 },
 
   printf("Testing strlen...\n");
   tests_passing = runStrlenTest(strlen, verbose) && tests_passing;
 
+  printf("Testing strcpy...\n");
+  tests_passing = runStrcpyTest(strcpy, verbose) && tests_passing;
+
+  printf("Testing strcat...\n");
+  tests_passing = runStrcatTest(strcat, verbose) && tests_passing;
+
   return (tests_passing ? 0 : 1);
 }