Initial commit.

This commit is contained in:
Peter Goodman
2017-10-27 16:34:58 -04:00
commit 6249ec6208
10 changed files with 985 additions and 0 deletions
+241
View File
@@ -0,0 +1,241 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_MCTEST_MCTEST_H_
#define INCLUDE_MCTEST_MCTEST_H_
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Symbolize the data in the range `[begin, end)`. */
extern void McTest_SymbolizeData(void *begin, void *end);
inline static void *McTest_Malloc(size_t num_bytes) {
void *data = malloc(num_bytes);
uintptr_t data_end = ((uintptr_t) data) + num_bytes;
McTest_SymbolizeData(data, (void *) data_end);
return data;
}
#define MCTEST_MAKE_SYMBOLIC_ARRAY(Tname, tname) \
inline static tname *McTest_Symbolic ## Tname ## Array(size_t num_elms) { \
tname *arr = (tname *) malloc(sizeof(tname) * num_elms); \
McTest_SymbolizeData(arr, &(arr[num_elms])); \
return arr; \
}
MCTEST_MAKE_SYMBOLIC_ARRAY(Int64, int64_t)
MCTEST_MAKE_SYMBOLIC_ARRAY(UInt64, uint64_t)
MCTEST_MAKE_SYMBOLIC_ARRAY(Int, int)
MCTEST_MAKE_SYMBOLIC_ARRAY(UInt, uint32_t)
MCTEST_MAKE_SYMBOLIC_ARRAY(Short, int16_t)
MCTEST_MAKE_SYMBOLIC_ARRAY(UShort, uint16_t)
MCTEST_MAKE_SYMBOLIC_ARRAY(Char, char)
MCTEST_MAKE_SYMBOLIC_ARRAY(UChar, unsigned char)
#undef MCTEST_MAKE_SYMBOLIC_ARRAY
/* Return a symbolic C string. */
inline static char *McTest_CStr(size_t len) {
char *str = (char *) malloc(sizeof(char) * len);
if (len) {
McTest_SymbolizeData(str, &(str[len - 1]));
str[len - 1] = '\0';
}
return str;
}
/* Creates an assumption about a symbolic value. Returns `1` if the assumption
* can hold and was asserted. */
extern int McTest_Assume(int expr);
/* Asserts that `expr` must hold. */
inline static void McTest_Assert(int expr) {
if (McTest_Assume(!expr)) {
abort();
}
}
/* Return a symbolic value of a given type. */
extern int McTest_Bool(void);
extern size_t McTest_Size(void);
extern uint64_t McTest_UInt64(void);
extern uint32_t McTest_UInt(void);
inline static int64_t McTest_Int64(void) {
return (int64_t) McTest_UInt64();
}
inline static int32_t McTest_Int(void) {
return (int32_t) McTest_UInt();
}
inline static uint16_t McTest_UShort(void) {
return (uint16_t) McTest_UInt();
}
inline static int16_t McTest_Short(void) {
return (int16_t) McTest_UInt();
}
inline static unsigned char McTest_UChar(void) {
return (unsigned char) McTest_UInt();
}
inline static char McTest_Char(void) {
return (char) McTest_UInt();
}
/* Return a symbolic value in a the range `[low_inc, high_inc]`. */
#define MCTEST_MAKE_SYMBOLIC_RANGE(Tname, tname) \
inline static tname McTest_ ## Tname ## InRange( \
tname low, tname high) { \
tname x = McTest_ ## Tname(); \
(void) McTest_Assume(low <= x && x <= high); \
return x; \
}
MCTEST_MAKE_SYMBOLIC_RANGE(Int64, int64_t)
MCTEST_MAKE_SYMBOLIC_RANGE(UInt64, uint64_t)
MCTEST_MAKE_SYMBOLIC_RANGE(Int, int)
MCTEST_MAKE_SYMBOLIC_RANGE(UInt, uint32_t)
MCTEST_MAKE_SYMBOLIC_RANGE(Short, int16_t)
MCTEST_MAKE_SYMBOLIC_RANGE(UShort, uint16_t)
MCTEST_MAKE_SYMBOLIC_RANGE(Char, char)
MCTEST_MAKE_SYMBOLIC_RANGE(UChar, unsigned char)
#undef MCTEST_MAKE_SYMBOLIC_RANGE
/* Return a symbolic value of a given type. */
extern int McTest_Bool(void);
extern size_t McTest_Size(void);
extern uint64_t McTest_UInt64(void);
extern int64_t McTest_Int64(void);
extern uint32_t McTest_UInt(void);
extern int32_t McTest_Int(void);
extern uint16_t McTest_UShort(void);
extern int16_t McTest_Short(void);
extern unsigned char McTest_UChar(void);
extern char McTest_Char(void);
/* Predicates to check whether or not a particular value is symbolic */
extern int McTest_IsSymbolicUInt(uint32_t x);
inline static int McTest_IsSymbolicInt(int x) {
return McTest_IsSymbolicUInt((uint32_t) x);
}
inline static int McTest_IsSymbolicUShort(uint16_t x) {
return McTest_IsSymbolicUInt((uint32_t) x);
}
inline static int McTest_IsSymbolicShort(int16_t x) {
return McTest_IsSymbolicUInt((uint32_t) (uint16_t) x);
}
inline static int McTest_IsSymbolicUChar(unsigned char x) {
return McTest_IsSymbolicUInt((uint32_t) x);
}
inline static int McTest_IsSymbolicChar(char x) {
return McTest_IsSymbolicUInt((uint32_t) (unsigned char) x);
}
inline static int McTest_IsSymbolicUInt64(uint64_t x) {
return McTest_IsSymbolicUInt((uint32_t) x) ||
McTest_IsSymbolicUInt((uint32_t) (x >> 32U));
}
inline static int McTest_IsSymbolicInt64(int64_t x) {
return McTest_IsSymbolicUInt64((uint64_t) x);
}
inline static int McTest_IsSymbolicBool(int x) {
return McTest_IsSymbolicInt(x);
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpointer-to-int-cast"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
inline static int McTest_IsSymbolicPtr(void *x) {
if (sizeof(void *) == 8) {
return McTest_IsSymbolicUInt64((uint64_t) x);
} else {
return McTest_IsSymbolicUInt((uint32_t) x);
}
}
#pragma GCC diagnostic pop
#pragma clang diagnostic pop
inline static int McTest_IsSymbolicFloat(float x) {
return McTest_IsSymbolicUInt(*((uint32_t *) &x));
}
inline static int McTest_IsSymbolicDouble(double x) {
return McTest_IsSymbolicUInt64(*((uint64_t *) &x));
}
#define _MCTEST_TO_STR(a) __MCTEST_TO_STR(a)
#define __MCTEST_TO_STR(a) #a
#ifdef __cplusplus
# define MCTEST_EXTERN_C extern "C"
#else
# define MCTEST_EXTERN_C
#endif
#define McTest_EntryPoint(test_name) \
_McTest_EntryPoint(test_name, __FILE__, __LINE__)
#define _McTest_EntryPoint(test_name, file, line) \
static void McTest_Run_ ## test_name (void); \
__attribute__((noinline, used)) \
MCTEST_EXTERN_C void McTest_Register_ ## test_name (void) { \
__asm__ __volatile__ ( \
".pushsection .mctest_strtab,\"a\" \n" \
"1: \n" \
".asciz \"" _MCTEST_TO_STR(test_name) "\" \n" \
"2: \n" \
".asciz \"" file "\" \n" \
".popsection \n" \
".pushsection .mctest_entrypoints,\"a\" \n" \
".balign 16 \n" \
".quad %p0 \n" \
".quad 1b \n" \
".quad 2b \n" \
".quad " _MCTEST_TO_STR(line) " \n" \
".popsection \n" \
: \
: "i"(McTest_Run_ ## test_name) \
); \
} \
void McTest_Run_ ## test_name(void)
#ifdef __cplusplus
} /* extern C */
#endif /* __cplusplus */
#endif /* INCLUDE_MCTEST_MCTEST_H_ */
+149
View File
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_MCTEST_MCTEST_HPP_
#define INCLUDE_MCTEST_MCTEST_HPP_
#include <mctest/McTest.h>
#include <string>
#include <utility>
#include <vector>
namespace mctest {
inline static void *Malloc(size_t num_bytes) {
return McTest_Malloc(num_bytes);
}
inline static void SymbolizeData(void *begin, void *end) {
McTest_SymbolizeData(begin, end);
}
inline static bool Bool(void) {
return static_cast<bool>(McTest_Bool());
}
inline static size_t Size(void) {
return McTest_Size();
}
inline static uint64_t UInt64(void) {
return McTest_UInt64();
}
inline static int64_t Int64(void) {
return McTest_Int64();
}
inline static uint32_t UInt(void) {
return McTest_UInt();
}
inline static int32_t Int(void) {
return McTest_Int();
}
inline static uint16_t UShort(void) {
return McTest_UShort();
}
inline static int16_t Short(void) {
return McTest_Short();
}
inline static unsigned char UChar(void) {
return McTest_UChar();
}
inline static char Char(void) {
return McTest_Char();
}
inline static int IsSymbolic(uint64_t x) {
return McTest_IsSymbolicUInt64(x);
}
inline static int IsSymbolic(int64_t x) {
return McTest_IsSymbolicInt64(x);
}
inline static int IsSymbolic(uint32_t x) {
return McTest_IsSymbolicUInt(x);
}
inline static int IsSymbolic(int32_t x) {
return McTest_IsSymbolicInt(x);
}
inline static int IsSymbolic(uint16_t x) {
return McTest_IsSymbolicUShort(x);
}
inline static int IsSymbolic(int16_t x) {
return McTest_IsSymbolicShort(x);
}
inline static int IsSymbolic(unsigned char x) {
return McTest_IsSymbolicUChar(x);
}
inline static int IsSymbolic(char x) {
return McTest_IsSymbolicChar(x);
}
inline static int IsSymbolic(float x) {
return McTest_IsSymbolicFloat(x);
}
inline static int IsSymbolic(double x) {
return McTest_IsSymbolicDouble(x);
}
inline static int IsSymbolic(void *x) {
return McTest_IsSymbolicPtr(x);
}
#if 199711L < __cplusplus
/* Returns a symbolic container (where it makes sense). Container entries
* do not necessarily need to be contiguous. */
template <typename ContainerT, typename... Args>
inline static ContainerT Symbolic(Args&& ...args) {
ContainerT cont(std::forward<Args...>(args)...);
if (!cont.empty()) {
for (auto &entry : cont) {
auto entry_ptr = &entry;
McTest_SymbolizeData(entry_ptr, &(entry_ptr[1]));
}
}
return cont;
}
#endif // 199711L < __cplusplus
// Returns a symbolic std::string of length `len`.
inline static std::string Str(size_t len) {
std::string str(len);
if (len) {
McTest_SymbolizeData(&(str.begin()), &(str.end()));
}
return str;
}
} // namespace mctest
#endif // INCLUDE_MCTEST_MCTEST_HPP_
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <mctest/McTest.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
static uint32_t gPlaybookIndex = 0;
static uint32_t gPlaybook[8192] = {};
void McTest_SymbolizeData(void *begin, void *end) {
(void) begin;
(void) end;
}
/* Return a symbolic value of a given type. */
int McTest_Bool(void) {
return 0;
}
size_t McTest_Size(void) {
return 0;
}
uint64_t McTest_UInt64(void) {
return 0;
}
uint32_t McTest_UInt(void) {
return 0;
}
int McTest_Assume(int expr) {
assert(expr);
return 1;
}
int McTest_IsSymbolicUInt(uint32_t x) {
(void) x;
return 0;
}
void McTest_DoneTestCase(void) {
exit(EXIT_SUCCESS);
}
/* McTest implements the `main` function so that test code can focus on tests */
int main(void) {
#if defined(__x86_64__) || defined(__i386__) || defined(_M_X86)
asm("ud2; .asciz \"I'm McTest'in it\";");
#else
# error "Unsupported platform (for now)."
#endif
return EXIT_SUCCESS;
}
#ifdef __cplusplus
} /* extern C */
#endif /* __cplusplus */