Add strlen tests. DO NOT MERGE

Merge from internal master.

(cherry-picked from from commit a63c049f23c49b6345bf2c845a415109c5471ebe)

Change-Id: I443a866a4b146a8043dd84cf6b7c090ecd529519
diff --git a/libc_test/main.cpp b/libc_test/main.cpp
index 8b012b6..3c57f41 100644
--- a/libc_test/main.cpp
+++ b/libc_test/main.cpp
@@ -34,6 +34,9 @@
 #define MAX_STRCMP_TEST_SIZE      1024
 #define MAX_STRCMP_BUFFER_SIZE    (3 * MAX_STRCMP_TEST_SIZE)
 
+#define MAX_STRLEN_TEST_SIZE      1024
+#define MAX_STRLEN_BUFFER_SIZE    (3 * MAX_STRLEN_TEST_SIZE)
+
 // Return a pointer into the current string with the specified alignment.
 void *getAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
   uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
@@ -347,6 +350,137 @@
   return true;
 }
 
+bool doStrlenCheck(size_t size, char *string, int align, int or_mask,
+                   size_t (*test_strlen)(const char *), bool verbose) {
+  char *aligned_string = reinterpret_cast<char*>(getAlignedPtr(string, align, or_mask));
+  size_t len;
+  if (verbose) {
+    printf("Testing size %d, align=%p[%d,%d]\n", size, aligned_string, align, or_mask);
+  }
+
+  aligned_string[size] = '\0';
+  len = test_strlen(aligned_string);
+  if (len != size) {
+    printf("Failed at size %d, length returned %u, align=%p[%d,%d]\n",
+           size, len, aligned_string, align, or_mask);
+    return false;
+  }
+
+  if (verbose) {
+    printf("Testing size %d with extra zeros after string, align=%p[%d,%d]\n",
+           size, aligned_string, align, or_mask);
+  }
+
+  for (size_t j = size+1; j <= size+16; j++) {
+    aligned_string[j] = '\0';
+  }
+
+  len = test_strlen(aligned_string);
+  if (len != size) {
+    printf("Failed at size %d, length returned %u with zeroes after string, align=%p[%d,%d]\n",
+           size, len, aligned_string, align, or_mask);
+    return false;
+  }
+
+  for (size_t j = size; j <= size+16; j++) {
+    aligned_string[j] = (char)(32 + (j % 96));
+  }
+  return true;
+}
+
+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));
+  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] = {
+    // All zeroes to use the values returned from malloc.
+    { 0, 0 },
+
+    { 1, 0 },
+    { 2, 0 },
+    { 4, 0 },
+    { 8, 0 },
+    { 16, 0 },
+    { 32, 0 },
+
+    { 8, 1 },
+    { 8, 2 },
+    { 8, 3 },
+
+    { 4, 1 },
+    { 4, 2 },
+    { 4, 3 },
+  };
+
+  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++) {
+      if (!doStrlenCheck(j, string, aligns[i][0], aligns[i][1], test_strlen, verbose)) {
+        return false;
+      }
+    }
+  }
+
+  printf("  Verifying strlen does not read past end of string.\n");
+
+  // In order to verify that strlen is not reading past the end of the
+  // string, create strings that end near unreadable memory.
+  long pagesize = sysconf(_SC_PAGE_SIZE);
+  char *memory = (char*)memalign(pagesize, 2 * pagesize);
+  if (memory == NULL) {
+    perror("Unable to allocate memory.\n");
+    return false;
+  }
+
+  // Make the second page unreadable and unwritable.
+  if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
+    perror("Unable to set protection of page.\n");
+    return false;
+  }
+
+  size_t max_size = pagesize < MAX_STRLEN_TEST_SIZE ? pagesize-1 : MAX_STRLEN_TEST_SIZE;
+  for (long i = 0; i < pagesize; i++) {
+    memory[i] = (char)(32 + (i % 96));
+  }
+
+  size_t len;
+  for (size_t i = 0; i < sizeof(aligns)/sizeof(int[2]); i++) {
+    for (size_t j = 0; j <= max_size; j++) {
+      string = &memory[pagesize-j-1];
+      string[j] = '\0';
+
+      if (verbose) {
+        printf("Testing size %d overread, align=%p[%d,%d]\n",
+               j, string, aligns[i][0], aligns[i][1]);
+      }
+      len = test_strlen(string);
+      if (len != j) {
+        printf("    Failed at size %u, returned %u, align=%p[%d,%d]\n",
+               j, len, string, aligns[i][0], aligns[i][1]);
+        return false;
+      }
+      string[j] = (char)(32 + (j % 96));
+    }
+  }
+
+  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.
@@ -587,6 +721,7 @@
   }
 
   bool tests_passing = true;
+
   printf("Testing strcmp...\n");
   tests_passing = runStrcmpTest(strcmp, verbose) && tests_passing;
 
@@ -596,5 +731,8 @@
   printf("Testing memset...\n");
   tests_passing = runMemsetTest(memset, verbose) && tests_passing;
 
+  printf("Testing strlen...\n");
+  tests_passing = runStrlenTest(strlen, verbose) && tests_passing;
+
   return (tests_passing ? 0 : 1);
 }