Made it so that tests can be run on their own, independent of a symbolic executor. This will open up libFuzzer support, and concrete execution of solved-for test case inputs. Removed all stuff related to sections. Made tests get registered via initializers. Working on exposing the API functions to be hooked by Manticore via a special system call with addres 0x41414141. Split the Angr version out into the mctest-angr binary, and going to try to make the mctest binary use Manticore.
This commit is contained in:
96
src/include/mctest/Compiler.h
Normal file
96
src/include/mctest/Compiler.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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_COMPILER_H_
|
||||
#define INCLUDE_MCTEST_COMPILER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Stringify a macro parameter. */
|
||||
#define MCTEST_TO_STR(a) _MCTEST_TO_STR(a)
|
||||
#define _MCTEST_TO_STR(a) __MCTEST_TO_STR(a)
|
||||
#define __MCTEST_TO_STR(a) #a
|
||||
|
||||
/* Mark a function as not returning. */
|
||||
#if defined(_MSC_VER)
|
||||
# define MCTEST_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
# define MCTEST_NORETURN __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
/* Mark a function for inlining. */
|
||||
#if defined(_MSC_VER)
|
||||
# define MCTEST_INLINE __forceinline
|
||||
# define MCTEST_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
# define MCTEST_INLINE inline __attribute__((always_inline))
|
||||
# define MCTEST_NOINLINE __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
/* Introduce a trap instruction to halt execution. */
|
||||
#if defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
# define McTest_Trap __debugbreak
|
||||
#else
|
||||
# define McTest_Trap __builtin_trap
|
||||
#endif
|
||||
|
||||
/* Wrap a block of code in `extern "C"` if we are compiling with a C++
|
||||
* compiler. */
|
||||
#ifdef __cplusplus
|
||||
# define MCTEST_BEGIN_EXTERN_C extern "C" {
|
||||
# define MCTEST_END_EXTERN_C }
|
||||
#else
|
||||
# define MCTEST_BEGIN_EXTERN_C
|
||||
# define MCTEST_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
/* Initializer/finalizer sample for MSVC and GCC/Clang.
|
||||
* 2010-2016 Joe Lowe. Released into the public domain.
|
||||
*
|
||||
* See: https://stackoverflow.com/a/2390626/247591 */
|
||||
#ifdef __cplusplus
|
||||
# define MCTEST_INITIALIZER(f) \
|
||||
static void f(void); \
|
||||
struct f ##_t_ { \
|
||||
f##_t_(void) { \
|
||||
f(); \
|
||||
} \
|
||||
}; \
|
||||
static f##_t_ f##_; \
|
||||
static void f(void)
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
# pragma section(".CRT$XCU",read)
|
||||
# define MCTEST_INITIALIZER2_(f, p) \
|
||||
static void f(void); \
|
||||
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
|
||||
__pragma(comment(linker,"/include:" p #f "_")) \
|
||||
static void f(void)
|
||||
|
||||
# ifdef _WIN64
|
||||
# define MCTEST_INITIALIZER(f) MCTEST_INITIALIZER2_(f,"")
|
||||
# else
|
||||
# define MCTEST_INITIALIZER(f) MCTEST_INITIALIZER2_(f,"_")
|
||||
# endif
|
||||
#else
|
||||
# define MCTEST_INITIALIZER(f) \
|
||||
static void f(void) __attribute__((constructor)); \
|
||||
static void f(void)
|
||||
#endif
|
||||
|
||||
#endif /* INCLUDE_MCTEST_COMPILER_H_ */
|
||||
@@ -22,14 +22,14 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <mctest/Compiler.h>
|
||||
|
||||
#ifdef assert
|
||||
# undef assert
|
||||
#endif
|
||||
#define assert McTest_Assert
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
MCTEST_BEGIN_EXTERN_C
|
||||
|
||||
/* Return a symbolic value of a given type. */
|
||||
extern int McTest_Bool(void);
|
||||
@@ -46,7 +46,7 @@ extern int8_t McTest_Char(void);
|
||||
/* 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) {
|
||||
MCTEST_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);
|
||||
@@ -54,7 +54,8 @@ inline static void *McTest_Malloc(size_t num_bytes) {
|
||||
}
|
||||
|
||||
#define MCTEST_MAKE_SYMBOLIC_ARRAY(Tname, tname) \
|
||||
inline static tname *McTest_Symbolic ## Tname ## Array(size_t num_elms) { \
|
||||
MCTEST_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; \
|
||||
@@ -72,7 +73,7 @@ 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) {
|
||||
MCTEST_INLINE static char *McTest_CStr(size_t len) {
|
||||
char *str = (char *) malloc(sizeof(char) * len);
|
||||
if (len) {
|
||||
McTest_SymbolizeData(str, &(str[len - 1]));
|
||||
@@ -87,14 +88,14 @@ extern void _McTest_Assume(int expr);
|
||||
|
||||
#define McTest_Assume(x) _McTest_Assume(!!(x))
|
||||
|
||||
__attribute__((noreturn))
|
||||
MCTEST_NORETURN
|
||||
extern void McTest_Fail(void);
|
||||
|
||||
__attribute__((noreturn))
|
||||
MCTEST_NORETURN
|
||||
extern void McTest_Pass(void);
|
||||
|
||||
/* Asserts that `expr` must hold. */
|
||||
inline static void McTest_Assert(int expr) {
|
||||
MCTEST_INLINE static void McTest_Assert(int expr) {
|
||||
if (!expr) {
|
||||
McTest_Fail();
|
||||
}
|
||||
@@ -102,14 +103,13 @@ inline static void McTest_Assert(int expr) {
|
||||
|
||||
/* 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( \
|
||||
MCTEST_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(Size, size_t)
|
||||
MCTEST_MAKE_SYMBOLIC_RANGE(Int64, int64_t)
|
||||
MCTEST_MAKE_SYMBOLIC_RANGE(UInt64, uint64_t)
|
||||
@@ -125,88 +125,96 @@ MCTEST_MAKE_SYMBOLIC_RANGE(UChar, unsigned char)
|
||||
/* 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) {
|
||||
/* The following predicates are implemented in terms of `McTest_IsSymbolicUInt`.
|
||||
* This simplifies the portability of hooking this predicate interface across
|
||||
* architectures, because basically all hooking mechanisms know how to get at
|
||||
* the first integer argument. Passing in floating point values, or 64-bit
|
||||
* integers on 32-bit architectures, can be more subtle. */
|
||||
|
||||
MCTEST_INLINE static int McTest_IsSymbolicInt(int x) {
|
||||
return McTest_IsSymbolicUInt((uint32_t) x);
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicUShort(uint16_t x) {
|
||||
MCTEST_INLINE static int McTest_IsSymbolicUShort(uint16_t x) {
|
||||
return McTest_IsSymbolicUInt((uint32_t) x);
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicShort(int16_t x) {
|
||||
MCTEST_INLINE static int McTest_IsSymbolicShort(int16_t x) {
|
||||
return McTest_IsSymbolicUInt((uint32_t) (uint16_t) x);
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicUChar(unsigned char x) {
|
||||
MCTEST_INLINE static int McTest_IsSymbolicUChar(unsigned char x) {
|
||||
return McTest_IsSymbolicUInt((uint32_t) x);
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicChar(char x) {
|
||||
MCTEST_INLINE static int McTest_IsSymbolicChar(char x) {
|
||||
return McTest_IsSymbolicUInt((uint32_t) (unsigned char) x);
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicUInt64(uint64_t x) {
|
||||
MCTEST_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) {
|
||||
MCTEST_INLINE static int McTest_IsSymbolicInt64(int64_t x) {
|
||||
return McTest_IsSymbolicUInt64((uint64_t) x);
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicBool(int x) {
|
||||
MCTEST_INLINE static int McTest_IsSymbolicBool(int x) {
|
||||
return McTest_IsSymbolicInt(x);
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicFloat(float x) {
|
||||
MCTEST_INLINE static int McTest_IsSymbolicFloat(float x) {
|
||||
return McTest_IsSymbolicUInt(*((uint32_t *) &x));
|
||||
}
|
||||
|
||||
inline static int McTest_IsSymbolicDouble(double x) {
|
||||
MCTEST_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_BEGIN_EXTERN_C extern "C" {
|
||||
# define MCTEST_END_EXTERN_C }
|
||||
#else
|
||||
# define MCTEST_BEGIN_EXTERN_C
|
||||
# define MCTEST_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
/* Used to define the entrypoint of a test case. */
|
||||
#define McTest_EntryPoint(test_name) \
|
||||
_McTest_EntryPoint(test_name, __FILE__, __LINE__)
|
||||
|
||||
struct __attribute__((packed)) McTest_TestInfo {
|
||||
/* Contains information about a test case */
|
||||
struct McTest_TestInfo {
|
||||
struct McTest_TestInfo *prev;
|
||||
void (*test_func)(void);
|
||||
const char *test_name;
|
||||
const char *file_name;
|
||||
unsigned line_number;
|
||||
uint8_t padding[28 - (3 * sizeof(void *))];
|
||||
};
|
||||
|
||||
/* Pointer to the last registered `TestInfo` structure. */
|
||||
extern struct McTest_TestInfo *McTest_LastTestInfo;
|
||||
|
||||
/* Defines the entrypoint of a test case. This creates a data structure that
|
||||
* contains the information about the test, and then creates an initializer
|
||||
* function that runs before `main` that registers the test entrypoint with
|
||||
* McTest. */
|
||||
#define _McTest_EntryPoint(test_name, file, line) \
|
||||
static void McTest_Test_ ## test_name (void); \
|
||||
static void McTest_Run_ ## test_name (void) { \
|
||||
McTest_Test_ ## test_name(); \
|
||||
McTest_Pass(); \
|
||||
} \
|
||||
MCTEST_BEGIN_EXTERN_C \
|
||||
struct McTest_TestInfo McTest_Register_ ## test_name \
|
||||
__attribute__((section(".mctest_funcs"))) = { \
|
||||
static struct McTest_TestInfo McTest_Info_ ## test_name = { \
|
||||
NULL, \
|
||||
McTest_Run_ ## test_name, \
|
||||
_MCTEST_TO_STR(test_name), \
|
||||
MCTEST_TO_STR(test_name), \
|
||||
file, \
|
||||
line \
|
||||
line, \
|
||||
}; \
|
||||
MCTEST_END_EXTERN_C \
|
||||
MCTEST_INITIALIZER(McTest_Register_ ## test_name) { \
|
||||
McTest_Info_ ## test_name.prev = McTest_LastTestInfo; \
|
||||
McTest_LastTestInfo = &(McTest_Info_ ## test_name); \
|
||||
} \
|
||||
void McTest_Test_ ## test_name(void)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern C */
|
||||
#endif /* __cplusplus */
|
||||
/* Start McTest and run the tests. Returns the number of failed tests. */
|
||||
extern int McTest_Run(void);
|
||||
|
||||
MCTEST_END_EXTERN_C
|
||||
|
||||
#endif /* INCLUDE_MCTEST_MCTEST_H_ */
|
||||
|
||||
@@ -25,95 +25,95 @@
|
||||
|
||||
namespace mctest {
|
||||
|
||||
inline static void *Malloc(size_t num_bytes) {
|
||||
MCTEST_INLINE static void *Malloc(size_t num_bytes) {
|
||||
return McTest_Malloc(num_bytes);
|
||||
}
|
||||
|
||||
inline static void SymbolizeData(void *begin, void *end) {
|
||||
MCTEST_INLINE static void SymbolizeData(void *begin, void *end) {
|
||||
McTest_SymbolizeData(begin, end);
|
||||
}
|
||||
|
||||
inline static bool Bool(void) {
|
||||
MCTEST_INLINE static bool Bool(void) {
|
||||
return static_cast<bool>(McTest_Bool());
|
||||
}
|
||||
|
||||
inline static size_t Size(void) {
|
||||
MCTEST_INLINE static size_t Size(void) {
|
||||
return McTest_Size();
|
||||
}
|
||||
|
||||
inline static uint64_t UInt64(void) {
|
||||
MCTEST_INLINE static uint64_t UInt64(void) {
|
||||
return McTest_UInt64();
|
||||
}
|
||||
|
||||
inline static int64_t Int64(void) {
|
||||
MCTEST_INLINE static int64_t Int64(void) {
|
||||
return McTest_Int64();
|
||||
}
|
||||
|
||||
inline static uint32_t UInt(void) {
|
||||
MCTEST_INLINE static uint32_t UInt(void) {
|
||||
return McTest_UInt();
|
||||
}
|
||||
|
||||
inline static int32_t Int(void) {
|
||||
MCTEST_INLINE static int32_t Int(void) {
|
||||
return McTest_Int();
|
||||
}
|
||||
|
||||
inline static uint16_t UShort(void) {
|
||||
MCTEST_INLINE static uint16_t UShort(void) {
|
||||
return McTest_UShort();
|
||||
}
|
||||
|
||||
inline static int16_t Short(void) {
|
||||
MCTEST_INLINE static int16_t Short(void) {
|
||||
return McTest_Short();
|
||||
}
|
||||
|
||||
inline static unsigned char UChar(void) {
|
||||
MCTEST_INLINE static unsigned char UChar(void) {
|
||||
return McTest_UChar();
|
||||
}
|
||||
|
||||
inline static char Char(void) {
|
||||
MCTEST_INLINE static char Char(void) {
|
||||
return McTest_Char();
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(uint64_t x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(uint64_t x) {
|
||||
return McTest_IsSymbolicUInt64(x);
|
||||
}
|
||||
|
||||
inline static int IsSymbolic(int64_t x) {
|
||||
MCTEST_INLINE static int IsSymbolic(int64_t x) {
|
||||
return McTest_IsSymbolicInt64(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(uint32_t x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(uint32_t x) {
|
||||
return McTest_IsSymbolicUInt(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(int32_t x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(int32_t x) {
|
||||
return McTest_IsSymbolicInt(x);
|
||||
}
|
||||
|
||||
inline static int IsSymbolic(uint16_t x) {
|
||||
MCTEST_INLINE static int IsSymbolic(uint16_t x) {
|
||||
return McTest_IsSymbolicUShort(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(int16_t x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(int16_t x) {
|
||||
return McTest_IsSymbolicShort(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(unsigned char x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(unsigned char x) {
|
||||
return McTest_IsSymbolicUChar(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(char x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(char x) {
|
||||
return McTest_IsSymbolicChar(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(float x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(float x) {
|
||||
return McTest_IsSymbolicFloat(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(double x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(double x) {
|
||||
return McTest_IsSymbolicDouble(x);
|
||||
}
|
||||
|
||||
inline static bool IsSymbolic(void *x) {
|
||||
MCTEST_INLINE static bool IsSymbolic(void *x) {
|
||||
return IsSymbolic((uintptr_t) x);
|
||||
}
|
||||
|
||||
@@ -121,15 +121,15 @@ template <typename T>
|
||||
class Symbolic {
|
||||
public:
|
||||
template <typename... Args>
|
||||
inline Symbolic(Args&& ...args)
|
||||
MCTEST_INLINE Symbolic(Args&& ...args)
|
||||
: value(std::forward<Args...>(args)...) {}
|
||||
|
||||
inline Symbolic(void) {
|
||||
MCTEST_INLINE Symbolic(void) {
|
||||
T *val_ptr = &value;
|
||||
McTest_SymbolizeData(val_ptr, &(val_ptr[1]));
|
||||
}
|
||||
|
||||
inline operator T (void) const {
|
||||
MCTEST_INLINE operator T (void) const {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -139,17 +139,17 @@ class Symbolic {
|
||||
template <typename T>
|
||||
class SymbolicLinearContainer {
|
||||
public:
|
||||
inline explicit SymbolicLinearContainer(size_t len)
|
||||
MCTEST_INLINE explicit SymbolicLinearContainer(size_t len)
|
||||
: value(len) {
|
||||
if (len) {
|
||||
McTest_SymbolizeData(&(value.begin()), &(value.end()));
|
||||
}
|
||||
}
|
||||
|
||||
inline SymbolicLinearContainer(void)
|
||||
MCTEST_INLINE SymbolicLinearContainer(void)
|
||||
: SymbolicLinearContainer(McTest_SizeInRange(0, 32)) {}
|
||||
|
||||
inline operator T (void) const {
|
||||
MCTEST_INLINE operator T (void) const {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -174,9 +174,9 @@ class Symbolic<std::vector<T>> :
|
||||
template <> \
|
||||
class Symbolic<tname> { \
|
||||
public: \
|
||||
inline Symbolic(void) \
|
||||
MCTEST_INLINE Symbolic(void) \
|
||||
: value(McTest_ ## Tname()) {} \
|
||||
inline operator tname (void) const { \
|
||||
MCTEST_INLINE operator tname (void) const { \
|
||||
return value; \
|
||||
} \
|
||||
tname value; \
|
||||
|
||||
104
src/lib/McTest.c
104
src/lib/McTest.c
@@ -17,24 +17,47 @@
|
||||
#include <mctest/McTest.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__)
|
||||
# define _GNU_SOURCE
|
||||
# include <unistd.h> /* For `syscall` */
|
||||
#endif
|
||||
|
||||
volatile uint8_t McTest_Input[8192]
|
||||
__attribute__((section(".mctest_data")));
|
||||
MCTEST_BEGIN_EXTERN_C
|
||||
|
||||
uint32_t McTest_InputIndex = 0;
|
||||
/* Pointer to the last registers McTest_TestInfo data structure */
|
||||
struct McTest_TestInfo *McTest_LastTestInfo = NULL;
|
||||
|
||||
__attribute__((noreturn))
|
||||
enum {
|
||||
McTest_InputLength = 8192
|
||||
};
|
||||
|
||||
/* Byte buffer that will contain symbolic data that is used to supply requests
|
||||
* for symbolic values (e.g. `int`s). */
|
||||
static volatile uint8_t McTest_Input[McTest_InputLength];
|
||||
|
||||
/* Index into the `McTest_Input` array that tracks how many input bytes have
|
||||
* been consumed. */
|
||||
static uint32_t McTest_InputIndex = 0;
|
||||
|
||||
/* Jump buffer for returning to `McTest_Main`. */
|
||||
static jmp_buf McTest_ReturnToMain;
|
||||
|
||||
static int McTest_TestPassed = 0;
|
||||
|
||||
/* Mark this test as failing. */
|
||||
MCTEST_NORETURN
|
||||
extern void McTest_Fail(void) {
|
||||
exit(EXIT_FAILURE);
|
||||
McTest_TestPassed = 0;
|
||||
longjmp(McTest_ReturnToMain, 1);
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
/* Mark this test as passing. */
|
||||
MCTEST_NORETURN
|
||||
extern void McTest_Pass(void) {
|
||||
exit(EXIT_SUCCESS);
|
||||
McTest_TestPassed = 1;
|
||||
longjmp(McTest_ReturnToMain, 0);
|
||||
}
|
||||
|
||||
void McTest_SymbolizeData(void *begin, void *end) {
|
||||
@@ -99,15 +122,56 @@ int McTest_IsSymbolicUInt(uint32_t x) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void McTest_DoneTestCase(void) {
|
||||
exit(EXIT_SUCCESS);
|
||||
/* A McTest-specific symbol that is needed for hooking. */
|
||||
struct McTest_IndexEntry {
|
||||
const char * const name;
|
||||
void * const address;
|
||||
};
|
||||
|
||||
/* An index of symbols that the symbolic executors will hook or
|
||||
* need access to. */
|
||||
const struct McTest_IndexEntry McTest_API[] = {
|
||||
{"Pass", (void *) McTest_Pass},
|
||||
{"Fail", (void *) McTest_Fail},
|
||||
{"Assume", (void *) _McTest_Assume},
|
||||
{"IsSymbolicUInt", (void *) McTest_IsSymbolicUInt},
|
||||
{"InputBegin", (void *) &(McTest_Input[0])},
|
||||
{"InputEnd", (void *) &(McTest_Input[McTest_InputLength])},
|
||||
{"InputIndex", (void *) &McTest_InputIndex},
|
||||
{"LastTestInfo", (void *) &McTest_LastTestInfo},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
int McTest_Run(void) {
|
||||
|
||||
/* Manticore entrypoint. Manticore doesn't (yet?) support symbol lookups, so
|
||||
* we instead interpose on this fake system call, and discover the API table
|
||||
* via the first argument to the system call. */
|
||||
#if defined(_MSC_VER)
|
||||
# warning "TODO: Implement Windows interception support for Manticore."
|
||||
#else
|
||||
syscall(0x41414141, &McTest_API);
|
||||
#endif
|
||||
|
||||
int num_failed_tests = 0;
|
||||
for (struct McTest_TestInfo *info = McTest_LastTestInfo;
|
||||
info != NULL;
|
||||
info = info->prev) {
|
||||
|
||||
McTest_TestPassed = 0;
|
||||
if (!setjmp(McTest_ReturnToMain)) {
|
||||
printf("Running %s from %s:%u\n", info->test_name, info->file_name,
|
||||
info->line_number);
|
||||
info->test_func();
|
||||
|
||||
} else if (McTest_TestPassed) {
|
||||
printf(" %s Passed\n", info->test_name);
|
||||
} else {
|
||||
printf(" %s Failed\n", info->test_name);
|
||||
num_failed_tests += 1;
|
||||
}
|
||||
}
|
||||
return num_failed_tests;
|
||||
}
|
||||
|
||||
/* McTest implements the `main` function so that test code can focus on tests */
|
||||
int main(void) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern C */
|
||||
#endif /* __cplusplus */
|
||||
MCTEST_END_EXTERN_C
|
||||
|
||||
Reference in New Issue
Block a user