Files
clang-p2996/compiler-rt/test/builtins/Unit/clear_cache_test.c
Michal Gorny b81980a376 [test] Fix page address logic in clear_cache_test
Fix the logic used to calculate page boundaries in clear_cache_test to
use correct masks -- e.g. -4096 rather than -4095. The latter gives
incorrect result since:

  -4095 -> 0xfffff001
  -4096 -> 0xfffff000 (== ~4095)

The issue went unnoticed so far because the array alignment caused
the last bit not to be set. However, on 32-bit x86 no such alignment is
enforced and the wrong page address caused the test to fail.

Furthermore, obtain the page size from the system instead of hardcoding
4096.

Differential Revision: https://reviews.llvm.org/D28849

llvm-svn: 292729
2017-01-21 21:55:00 +00:00

98 lines
2.5 KiB
C

//===-- clear_cache_test.c - Test clear_cache -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#if defined(_WIN32)
#include <windows.h>
void __clear_cache(void* start, void* end)
{
if (!FlushInstructionCache(GetCurrentProcess(), start, end-start))
exit(1);
}
static uintptr_t get_page_size() {
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
}
#else
#include <unistd.h>
#include <sys/mman.h>
extern void __clear_cache(void* start, void* end);
static uintptr_t get_page_size() {
return sysconf(_SC_PAGE_SIZE);
}
#endif
typedef int (*pfunc)(void);
int func1()
{
return 1;
}
int func2()
{
return 2;
}
void *__attribute__((noinline))
memcpy_f(void *dst, const void *src, size_t n) {
// ARM and MIPS nartually align functions, but use the LSB for ISA selection
// (THUMB, MIPS16/uMIPS respectively). Ensure that the ISA bit is ignored in
// the memcpy
#if defined(__arm__) || defined(__mips__)
return (void *)((uintptr_t)memcpy(dst, (void *)((uintptr_t)src & ~1), n) |
((uintptr_t)src & 1));
#else
return memcpy(dst, (void *)((uintptr_t)src), n);
#endif
}
unsigned char execution_buffer[128];
int main()
{
// make executable the page containing execution_buffer
uintptr_t page_size = get_page_size();
char* start = (char*)((uintptr_t)execution_buffer & (-page_size));
char* end = (char*)((uintptr_t)(&execution_buffer[128+page_size]) & (-page_size));
#if defined(_WIN32)
DWORD dummy_oldProt;
MEMORY_BASIC_INFORMATION b;
if (!VirtualQuery(start, &b, sizeof(b)))
return 1;
if (!VirtualProtect(b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE, &b.Protect))
#else
if (mprotect(start, end-start, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
#endif
return 1;
// verify you can copy and execute a function
pfunc f1 = (pfunc)memcpy_f(execution_buffer, func1, 128);
__clear_cache(execution_buffer, &execution_buffer[128]);
if ((*f1)() != 1)
return 1;
// verify you can overwrite a function with another
pfunc f2 = (pfunc)memcpy_f(execution_buffer, func2, 128);
__clear_cache(execution_buffer, &execution_buffer[128]);
if ((*f2)() != 2)
return 1;
return 0;
}