Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | // SPDX-License-Identifier: GPL-2.0 #include <malloc.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <time.h> #include "utils.h" #define SIZE 256 #define ITERATIONS 10000 #define LARGE_SIZE (5 * 1024) #define LARGE_ITERATIONS 1000 #define LARGE_MAX_OFFSET 32 #define LARGE_SIZE_START 4096 /* This is big enough to fit LARGE_SIZE and works on 4K & 64K kernels */ #define MAP_SIZE (64 * 1024) #define MAX_OFFSET_DIFF_S1_S2 48 int vmx_count; int enter_vmx_ops(void) { vmx_count++; return 1; } void exit_vmx_ops(void) { vmx_count--; } int test_memcmp(const void *s1, const void *s2, size_t n); /* test all offsets and lengths */ static void test_one(char *s1, char *s2, unsigned long max_offset, unsigned long size_start, unsigned long max_size) { unsigned long offset, size; for (offset = 0; offset < max_offset; offset++) { for (size = size_start; size < (max_size - offset); size++) { int x, y; unsigned long i; y = memcmp(s1+offset, s2+offset, size); x = test_memcmp(s1+offset, s2+offset, size); if (((x ^ y) < 0) && /* Trick to compare sign */ ((x | y) != 0)) { /* check for zero */ printf("memcmp returned %d, should have returned %d (offset %ld size %ld)\n", x, y, offset, size); for (i = offset; i < offset+size; i++) printf("%02x ", s1[i]); printf("\n"); for (i = offset; i < offset+size; i++) printf("%02x ", s2[i]); printf("\n"); abort(); } if (vmx_count != 0) { printf("vmx enter/exit not paired.(offset:%ld size:%ld s1:%p s2:%p vc:%d\n", offset, size, s1, s2, vmx_count); printf("\n"); abort(); } } } } static int testcase(bool islarge) { unsigned long i, comp_size, alloc_size; char *p, *s1, *s2; int iterations; comp_size = (islarge ? LARGE_SIZE : SIZE); alloc_size = comp_size + MAX_OFFSET_DIFF_S1_S2; iterations = islarge ? LARGE_ITERATIONS : ITERATIONS; p = mmap(NULL, 4 * MAP_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); FAIL_IF(p == MAP_FAILED); /* Put s1/s2 at the end of a page */ s1 = p + MAP_SIZE - alloc_size; s2 = p + 3 * MAP_SIZE - alloc_size; /* And unmap the subsequent page to force a fault if we overread */ munmap(p + MAP_SIZE, MAP_SIZE); munmap(p + 3 * MAP_SIZE, MAP_SIZE); srandom(time(0)); for (i = 0; i < iterations; i++) { unsigned long j; unsigned long change; char *rand_s1 = s1; char *rand_s2 = s2; for (j = 0; j < alloc_size; j++) s1[j] = random(); rand_s1 += random() % MAX_OFFSET_DIFF_S1_S2; rand_s2 += random() % MAX_OFFSET_DIFF_S1_S2; memcpy(rand_s2, rand_s1, comp_size); /* change one byte */ change = random() % comp_size; rand_s2[change] = random() & 0xff; if (islarge) test_one(rand_s1, rand_s2, LARGE_MAX_OFFSET, LARGE_SIZE_START, comp_size); else test_one(rand_s1, rand_s2, SIZE, 0, comp_size); } srandom(time(0)); for (i = 0; i < iterations; i++) { unsigned long j; unsigned long change; char *rand_s1 = s1; char *rand_s2 = s2; for (j = 0; j < alloc_size; j++) s1[j] = random(); rand_s1 += random() % MAX_OFFSET_DIFF_S1_S2; rand_s2 += random() % MAX_OFFSET_DIFF_S1_S2; memcpy(rand_s2, rand_s1, comp_size); /* change multiple bytes, 1/8 of total */ for (j = 0; j < comp_size / 8; j++) { change = random() % comp_size; s2[change] = random() & 0xff; } if (islarge) test_one(rand_s1, rand_s2, LARGE_MAX_OFFSET, LARGE_SIZE_START, comp_size); else test_one(rand_s1, rand_s2, SIZE, 0, comp_size); } return 0; } static int testcases(void) { #ifdef __powerpc64__ // vcmpequd used in memcmp_64.S is v2.07 SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07)); #endif testcase(0); testcase(1); return 0; } int main(void) { test_harness_set_timeout(300); return test_harness(testcases, "memcmp"); } |