Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 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 <stdlib.h>
     18 #include <string.h>
     19 #include <sys/mman.h>
     20 
     21 #include <gtest/gtest.h>
     22 #include "buffer_tests.h"
     23 #include "utils.h"
     24 
     25 // For the comparison buffer tests, the maximum length to test for the
     26 // miscompare checks.
     27 #define MISCMP_MAX_LENGTH 512
     28 
     29 #define FENCEPOST_LENGTH 8
     30 
     31 static int g_single_aligns[][2] = {
     32   // Both buffers at same alignment.
     33   { 1, 0 },
     34   { 2, 0 },
     35   { 4, 0 },
     36   { 8, 0 },
     37   { 16, 0 },
     38   { 32, 0 },
     39   { 64, 0 },
     40   { 128, 0 },
     41 
     42   // General unaligned cases.
     43   { 4, 1 },
     44   { 4, 2 },
     45   { 4, 3 },
     46 
     47   { 8, 1 },
     48   { 8, 2 },
     49   { 8, 3 },
     50   { 8, 4 },
     51   { 8, 5 },
     52   { 8, 6 },
     53   { 8, 7 },
     54 
     55   { 128, 1 },
     56   { 128, 4 },
     57   { 128, 8 },
     58   { 128, 12 },
     59   { 128, 16 },
     60 };
     61 
     62 static const size_t g_single_aligns_len = sizeof(g_single_aligns)/sizeof(int[2]);
     63 
     64 // Set of multiple buffer alignment combinations to be used for string/memory
     65 // testing routines.
     66 static int g_double_aligns[][4] = {
     67   // Both buffers at same alignment.
     68   { 1, 0, 1, 0 },
     69   { 2, 0, 2, 0 },
     70   { 4, 0, 4, 0 },
     71   { 8, 0, 8, 0 },
     72   { 16, 0, 16, 0 },
     73   { 32, 0, 32, 0 },
     74   { 64, 0, 64, 0 },
     75   { 128, 0, 128, 0 },
     76 
     77   // Different word alignments between buffers.
     78   { 8, 0, 4, 0 },
     79   { 4, 0, 8, 0 },
     80   { 16, 0, 4, 0 },
     81   { 4, 0, 16, 0 },
     82 
     83   // General unaligned cases.
     84   { 4, 0, 4, 1 },
     85   { 4, 0, 4, 2 },
     86   { 4, 0, 4, 3 },
     87 
     88   { 4, 1, 4, 0 },
     89   { 4, 1, 4, 1 },
     90   { 4, 1, 4, 2 },
     91   { 4, 1, 4, 3 },
     92 
     93   { 4, 2, 4, 0 },
     94   { 4, 2, 4, 1 },
     95   { 4, 2, 4, 2 },
     96   { 4, 2, 4, 3 },
     97 
     98   { 4, 3, 4, 0 },
     99   { 4, 3, 4, 1 },
    100   { 4, 3, 4, 2 },
    101   { 4, 3, 4, 3 },
    102 
    103   { 8, 0, 8, 1 },
    104   { 8, 0, 8, 2 },
    105   { 8, 0, 8, 3 },
    106   { 8, 0, 8, 4 },
    107   { 8, 0, 8, 5 },
    108   { 8, 0, 8, 6 },
    109   { 8, 0, 8, 7 },
    110 
    111   { 8, 1, 8, 0 },
    112   { 8, 1, 8, 1 },
    113   { 8, 1, 8, 2 },
    114   { 8, 1, 8, 3 },
    115   { 8, 1, 8, 4 },
    116   { 8, 1, 8, 5 },
    117   { 8, 1, 8, 6 },
    118   { 8, 1, 8, 7 },
    119 
    120   { 8, 2, 8, 0 },
    121   { 8, 2, 8, 1 },
    122   { 8, 2, 8, 2 },
    123   { 8, 2, 8, 3 },
    124   { 8, 2, 8, 4 },
    125   { 8, 2, 8, 5 },
    126   { 8, 2, 8, 6 },
    127   { 8, 2, 8, 7 },
    128 
    129   { 8, 3, 8, 0 },
    130   { 8, 3, 8, 1 },
    131   { 8, 3, 8, 2 },
    132   { 8, 3, 8, 3 },
    133   { 8, 3, 8, 4 },
    134   { 8, 3, 8, 5 },
    135   { 8, 3, 8, 6 },
    136   { 8, 3, 8, 7 },
    137 
    138   { 8, 4, 8, 0 },
    139   { 8, 4, 8, 1 },
    140   { 8, 4, 8, 2 },
    141   { 8, 4, 8, 3 },
    142   { 8, 4, 8, 4 },
    143   { 8, 4, 8, 5 },
    144   { 8, 4, 8, 6 },
    145   { 8, 4, 8, 7 },
    146 
    147   { 8, 5, 8, 0 },
    148   { 8, 5, 8, 1 },
    149   { 8, 5, 8, 2 },
    150   { 8, 5, 8, 3 },
    151   { 8, 5, 8, 4 },
    152   { 8, 5, 8, 5 },
    153   { 8, 5, 8, 6 },
    154   { 8, 5, 8, 7 },
    155 
    156   { 8, 6, 8, 0 },
    157   { 8, 6, 8, 1 },
    158   { 8, 6, 8, 2 },
    159   { 8, 6, 8, 3 },
    160   { 8, 6, 8, 4 },
    161   { 8, 6, 8, 5 },
    162   { 8, 6, 8, 6 },
    163   { 8, 6, 8, 7 },
    164 
    165   { 8, 7, 8, 0 },
    166   { 8, 7, 8, 1 },
    167   { 8, 7, 8, 2 },
    168   { 8, 7, 8, 3 },
    169   { 8, 7, 8, 4 },
    170   { 8, 7, 8, 5 },
    171   { 8, 7, 8, 6 },
    172   { 8, 7, 8, 7 },
    173 
    174   { 128, 1, 128, 4 },
    175   { 128, 1, 128, 8 },
    176   { 128, 1, 128, 12 },
    177   { 128, 1, 128, 16 },
    178   { 128, 4, 128, 1 },
    179   { 128, 8, 128, 1 },
    180   { 128, 12, 128, 1 },
    181   { 128, 16, 128, 1 },
    182 };
    183 
    184 static const size_t g_double_aligns_len = sizeof(g_double_aligns)/sizeof(int[4]);
    185 
    186 static size_t SetIncrement(size_t len) {
    187   if (len >= 4096) {
    188     return 1024;
    189   } else if (len >= 1024) {
    190     return 256;
    191   }
    192   return 1;
    193 }
    194 
    195 // Return a pointer into the current buffer with the specified alignment.
    196 static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
    197   uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
    198   if (alignment > 0) {
    199       // When setting the alignment, set it to exactly the alignment chosen.
    200       // The pointer returned will be guaranteed not to be aligned to anything
    201       // more than that.
    202       ptr += alignment - (ptr & (alignment - 1));
    203       ptr |= alignment | or_mask;
    204   }
    205 
    206   return reinterpret_cast<void*>(ptr);
    207 }
    208 
    209 static void SetFencepost(uint8_t *buffer) {
    210   for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
    211     buffer[i] = 0xde;
    212     buffer[i+1] = 0xad;
    213   }
    214 }
    215 
    216 static void VerifyFencepost(uint8_t *buffer) {
    217   for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
    218     if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
    219       uint8_t expected_value;
    220       if (buffer[i] == 0xde) {
    221         i++;
    222         expected_value = 0xad;
    223       } else {
    224         expected_value = 0xde;
    225       }
    226       ASSERT_EQ(expected_value, buffer[i]);
    227     }
    228   }
    229 }
    230 
    231 // Malloc can return a tagged pointer, which is not accepted in mm system calls like mprotect
    232 // in the preliminary version of the syscall tagging support in the current Pixel 2 kernel.
    233 // Note: the final version of the kernel patchset may relax this requirement.
    234 static int MprotectHeap(void* addr, size_t len, int prot) {
    235   return mprotect(untag_address(addr), len, prot);
    236 }
    237 
    238 void RunSingleBufferAlignTest(
    239     size_t max_test_size, void (*test_func)(uint8_t*, size_t),
    240     size_t (*set_incr)(size_t)) {
    241   if (!set_incr) {
    242     set_incr = SetIncrement;
    243   }
    244 
    245   // Allocate one large buffer with lots of extra space so that we can
    246   // guarantee that the all possible alignments will fit.
    247   uint8_t *buf = new uint8_t[3*max_test_size];
    248 
    249   uint8_t *buf_align;
    250   for (size_t i = 0; i < g_single_aligns_len; i++) {
    251     size_t incr = 1;
    252     for (size_t len = 0; len <= max_test_size; len += incr) {
    253       incr = set_incr(len);
    254 
    255       buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
    256           buf+FENCEPOST_LENGTH, g_single_aligns[i][0], g_single_aligns[i][1]));
    257 
    258       SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
    259       SetFencepost(&buf_align[len]);
    260 
    261       test_func(buf_align, len);
    262 
    263       VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
    264       VerifyFencepost(&buf_align[len]);
    265     }
    266   }
    267   delete[] buf;
    268 }
    269 
    270 void RunSrcDstBufferAlignTest(
    271     size_t max_test_size, void (*test_func)(uint8_t*, uint8_t*, size_t),
    272     size_t (*set_incr)(size_t)) {
    273   if (!set_incr) {
    274     set_incr = SetIncrement;
    275   }
    276 
    277   // Allocate two large buffers for all of the testing.
    278   uint8_t* src = new uint8_t[3*max_test_size];
    279   uint8_t* dst = new uint8_t[3*max_test_size];
    280 
    281   uint8_t* src_align;
    282   uint8_t* dst_align;
    283   for (size_t i = 0; i < g_double_aligns_len; i++) {
    284     size_t incr = 1;
    285     for (size_t len = 0; len <= max_test_size; len += incr) {
    286       incr = set_incr(len);
    287 
    288       src_align =
    289           reinterpret_cast<uint8_t*>(GetAlignedPtr(
    290               src+FENCEPOST_LENGTH, g_double_aligns[i][0], g_double_aligns[i][1]));
    291       dst_align =
    292           reinterpret_cast<uint8_t*>(GetAlignedPtr(
    293               dst+FENCEPOST_LENGTH, g_double_aligns[i][2], g_double_aligns[i][3]));
    294       SetFencepost(&dst_align[-FENCEPOST_LENGTH]);
    295       SetFencepost(&dst_align[len]);
    296 
    297       test_func(src_align, dst_align, len);
    298 
    299       VerifyFencepost(&dst_align[-FENCEPOST_LENGTH]);
    300       VerifyFencepost(&dst_align[len]);
    301     }
    302   }
    303   delete[] src;
    304   delete[] dst;
    305 }
    306 
    307 void RunCmpBufferAlignTest(
    308     size_t max_test_size, void (*test_cmp_func)(uint8_t*, uint8_t*, size_t),
    309     void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t),
    310     size_t (*set_incr)(size_t)) {
    311   if (!set_incr) {
    312     set_incr = SetIncrement;
    313   }
    314 
    315   // Allocate two large buffers for all of the testing.
    316   uint8_t* buf1 = new uint8_t[3*max_test_size];
    317   uint8_t* buf2 = new uint8_t[3*max_test_size];
    318 
    319   uint8_t* buf1_align;
    320   uint8_t* buf2_align;
    321   for (size_t i = 0; i < g_double_aligns_len; i++) {
    322     size_t incr = 1;
    323     for (size_t len = 0; len <= max_test_size; len += incr) {
    324       incr = set_incr(len);
    325 
    326       buf1_align =
    327           reinterpret_cast<uint8_t*>(GetAlignedPtr(
    328               buf1, g_double_aligns[i][0], g_double_aligns[i][1]));
    329       buf2_align =
    330           reinterpret_cast<uint8_t*>(GetAlignedPtr(
    331               buf2, g_double_aligns[i][2], g_double_aligns[i][3]));
    332 
    333       // Check by putting all zeroes after both buffers.
    334       memset(buf1_align+len, 0, 32);
    335       memset(buf2_align+len, 0, 32);
    336       test_cmp_func(buf1_align, buf2_align, len);
    337 
    338       // Check by putting different values after both buffers.
    339       for (size_t j = 0; j < 32; j++) {
    340         buf1_align[len+j] = j;
    341         buf2_align[len+j] = j+1;
    342       }
    343       test_cmp_func(buf1_align, buf2_align, len);
    344 
    345       if (len > 0) {
    346         // Change the lengths of the buffers and verify that there are
    347         // miscompares.
    348         for (size_t len2 = len+1; len2 < len+32; len2++) {
    349           test_miscmp_func(buf1_align, buf2_align, len, len2);
    350           test_miscmp_func(buf1_align, buf2_align, len2, len);
    351         }
    352       }
    353     }
    354   }
    355   delete[] buf1;
    356   delete[] buf2;
    357 }
    358 
    359 void RunSingleBufferOverreadTest(void (*test_func)(uint8_t*, size_t)) {
    360   // In order to verify that functions are not reading past the end of the
    361   // src, create data that ends exactly at an unreadable memory boundary.
    362   size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
    363   uint8_t* memory;
    364   ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory), pagesize,
    365                              2*pagesize) == 0);
    366   memset(memory, 0x23, 2*pagesize);
    367 
    368   // Make the second page unreadable and unwritable.
    369   ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0);
    370 
    371   for (size_t i = 0; i < pagesize; i++) {
    372     uint8_t* buf = &memory[pagesize-i];
    373 
    374     test_func(buf, i);
    375   }
    376   ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
    377   free(memory);
    378 }
    379 
    380 void RunSrcDstBufferOverreadTest(void (*test_func)(uint8_t*, uint8_t*, size_t)) {
    381   // In order to verify that functions are not reading past the end of the
    382   // src, create data that ends exactly at an unreadable memory boundary.
    383   size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
    384   uint8_t* memory;
    385   ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory), pagesize,
    386                              2*pagesize) == 0);
    387   memset(memory, 0x23, 2*pagesize);
    388 
    389   // Make the second page unreadable and unwritable.
    390   ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0);
    391 
    392   uint8_t* dst_buffer = new uint8_t[2*pagesize];
    393   // Change the dst alignment as we change the source.
    394   for (size_t i = 0; i < 16; i++) {
    395     uint8_t* dst = &dst_buffer[i];
    396     for (size_t j = 0; j < pagesize; j++) {
    397       uint8_t* src = &memory[pagesize-j];
    398 
    399       test_func(src, dst, j);
    400     }
    401   }
    402   ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
    403   free(memory);
    404   delete[] dst_buffer;
    405 }
    406 
    407 void RunCmpBufferOverreadTest(
    408     void (*test_cmp_func)(uint8_t*, uint8_t*, size_t),
    409     void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t)) {
    410   // In order to verify that functions are not reading past the end of either
    411   // of the bufs, create both buffers that end exactly at an unreadable memory
    412   // boundary.
    413   size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
    414   uint8_t* memory1;
    415   ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory1), pagesize,
    416                              2*pagesize) == 0);
    417   memset(memory1, 0x23, 2*pagesize);
    418 
    419   // Make the second page unreadable and unwritable.
    420   ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_NONE) == 0);
    421 
    422   uint8_t* memory2;
    423   ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory2), pagesize,
    424                              2*pagesize) == 0);
    425   memset(memory2, 0x23, 2*pagesize);
    426 
    427   // Make the second page unreadable and unwritable.
    428   ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_NONE) == 0);
    429 
    430   for (size_t i = 0; i < pagesize; i++) {
    431     uint8_t* buf1 = &memory1[pagesize-i];
    432     uint8_t* buf2 = &memory2[pagesize-i];
    433 
    434     test_cmp_func(buf1, buf2, i);
    435   }
    436 
    437   // Don't cycle through pagesize, MISCMP_MAX_LENGTH bytes should be good.
    438   size_t miscmp_len;
    439   if (pagesize > MISCMP_MAX_LENGTH) {
    440     miscmp_len = MISCMP_MAX_LENGTH;
    441   } else {
    442     miscmp_len = pagesize;
    443   }
    444   for (size_t i = 1; i < miscmp_len; i++) {
    445     uint8_t* buf1 = &memory1[pagesize-i];
    446     for (size_t j = 1; j < miscmp_len; j++) {
    447       if (j == i)
    448         continue;
    449 
    450       uint8_t* buf2 = &memory2[pagesize-j];
    451 
    452       test_miscmp_func(buf1, buf2, i, j);
    453     }
    454   }
    455 
    456   ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
    457   ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
    458   free(memory1);
    459   free(memory2);
    460 }
    461