Merge pull request #156 from trailofbits/add_deepstate_string
stab at string generator
This commit is contained in:
@@ -142,9 +142,12 @@ DEEPSTATE_INLINE static int8_t DeepState_MaxChar(int8_t v) {
|
||||
return (int8_t) DeepState_MaxInt(v);
|
||||
}
|
||||
|
||||
/* Function to clean up generated strings, and any other DeepState-managed data. */
|
||||
extern void DeepState_CleanUp();
|
||||
|
||||
/* Returns `1` if `expr` is true, and `0` otherwise. This is kind of an indirect
|
||||
* way to take a symbolic value, introduce a fork, and on each size, replace its
|
||||
* value with a concrete value. */
|
||||
* value with a concrete value. */
|
||||
extern int DeepState_IsTrue(int expr);
|
||||
|
||||
/* Always returns `1`. */
|
||||
@@ -159,15 +162,22 @@ extern int DeepState_ZeroSink(int);
|
||||
/* Symbolize the data in the exclusive range `[begin, end)`. */
|
||||
extern void DeepState_SymbolizeData(void *begin, void *end);
|
||||
|
||||
/* Symbolize the data in the exclusive range `[begin, end)` with no nulls. */
|
||||
extern void DeepState_SymbolizeDataNoNull(void *begin, void *end);
|
||||
|
||||
/* Concretize some data in exclusive the range `[begin, end)`. Returns a
|
||||
* concrete pointer to the beginning of the concretized data. */
|
||||
extern void *DeepState_ConcretizeData(void *begin, void *end);
|
||||
|
||||
/* Return a symbolic C string of length `len`. */
|
||||
extern char *DeepState_CStr(size_t len);
|
||||
/* Assign a symbolic C string of _strlen_ `len` -- with only chars in allowed,
|
||||
* if `allowed` is non-null; needs space for null + len bytes */
|
||||
extern void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed);
|
||||
|
||||
/* Return a symbolic C string of strlen `len`. */
|
||||
extern char *DeepState_CStr_C(size_t len, const char* allowed);
|
||||
|
||||
/* Symbolize a C string */
|
||||
void DeepState_SymbolizeCStr(char *begin);
|
||||
void DeepState_SymbolizeCStr_C(char *begin, const char* allowed);
|
||||
|
||||
/* Concretize a C string. Returns a pointer to the beginning of the
|
||||
* concretized C string. */
|
||||
@@ -591,6 +601,7 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) {
|
||||
test_pid = fork();
|
||||
if (!test_pid) {
|
||||
DeepState_RunTest(test);
|
||||
/* No need to clean up in a fork; exit() is the ultimate garbage collector */
|
||||
}
|
||||
}
|
||||
int wstatus = 0;
|
||||
@@ -598,6 +609,7 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) {
|
||||
waitpid(test_pid, &wstatus, 0);
|
||||
} else {
|
||||
wstatus = DeepState_RunTestNoFork(test);
|
||||
DeepState_CleanUp();
|
||||
}
|
||||
|
||||
/* If we exited normally, the status code tells us if the test passed. */
|
||||
|
||||
@@ -314,7 +314,7 @@ static T Pump(T val, unsigned max=10) {
|
||||
}
|
||||
return Minimize(val);
|
||||
}
|
||||
|
||||
|
||||
template <typename... Args>
|
||||
inline static void ForAll(void (*func)(Args...)) {
|
||||
func(Symbolic<Args>()...);
|
||||
@@ -345,7 +345,7 @@ inline static char OneOf(const char *str) {
|
||||
}
|
||||
return str[DeepState_IntInRange(0, strlen(str) - 1)];
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline static const T &OneOf(const std::vector<T> &arr) {
|
||||
if (arr.empty()) {
|
||||
@@ -471,6 +471,35 @@ struct Comparer {
|
||||
}
|
||||
};
|
||||
|
||||
/* Like DeepState_AssignCStr_C, but fills in a null `allowed` value. */
|
||||
inline static void DeepState_AssignCStr(char* str, size_t len,
|
||||
const char* allowed = 0) {
|
||||
DeepState_AssignCStr_C(str, len, allowed);
|
||||
}
|
||||
|
||||
/* Like DeepState_AssignCStr, but Pumps through possible string sizes. */
|
||||
inline static void DeepState_AssignCStrUpToLen(char* str, size_t max_len,
|
||||
const char* allowed = 0) {
|
||||
uint32_t len = DeepState_UIntInRange(0, max_len);
|
||||
DeepState_AssignCStr_C(str, Pump(len, max_len+1), allowed);
|
||||
}
|
||||
|
||||
/* Like DeepState_CStr_C, but fills in a null `allowed` value. */
|
||||
inline static char* DeepState_CStr(size_t len, const char* allowed = 0) {
|
||||
return DeepState_CStr_C(len, allowed);
|
||||
}
|
||||
|
||||
/* Like DeepState_CStr, but Pumps through possible string sizes. */
|
||||
inline static char* DeepState_CStrUpToLen(size_t max_len, const char* allowed = 0) {
|
||||
uint32_t len = DeepState_UIntInRange(0, max_len);
|
||||
return DeepState_CStr_C(Pump(len, max_len+1), allowed);
|
||||
}
|
||||
|
||||
/* Like DeepState_Symbolize_CStr, but fills in null `allowed` value. */
|
||||
inline static void DeepState_SymbolizeCStr(char *begin, const char* allowed = 0) {
|
||||
DeepState_SymbolizeCStr_C(begin, allowed);
|
||||
}
|
||||
|
||||
} // namespace deepstate
|
||||
|
||||
#define ONE_OF ::deepstate::OneOf
|
||||
|
||||
@@ -56,6 +56,11 @@ int DeepState_UsingSymExec = 0;
|
||||
/* Set to 1 when we're using libFuzzer. */
|
||||
int DeepState_UsingLibFuzzer = 0;
|
||||
|
||||
/* Array of DeepState generated strings. Impossible for there to
|
||||
* be more than there are input bytes. Index stores where we are. */
|
||||
char* DeepState_GeneratedStrings[DeepState_InputSize];
|
||||
uint32_t DeepState_GeneratedStringsIndex = 0;
|
||||
|
||||
/* Pointer to the last registers DeepState_TestInfo data structure */
|
||||
struct DeepState_TestInfo *DeepState_LastTestInfo = NULL;
|
||||
|
||||
@@ -167,13 +172,63 @@ void DeepState_SymbolizeData(void *begin, void *end) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Symbolize the data in the exclusive range `[begin, end)` without null
|
||||
* characters included. Primarily useful for C strings. */
|
||||
void DeepState_SymbolizeDataNoNull(void *begin, void *end) {
|
||||
uintptr_t begin_addr = (uintptr_t) begin;
|
||||
uintptr_t end_addr = (uintptr_t) end;
|
||||
|
||||
if (begin_addr > end_addr) {
|
||||
DeepState_Abandon("Invalid data bounds for DeepState_SymbolizeData");
|
||||
} else if (begin_addr == end_addr) {
|
||||
return;
|
||||
} else {
|
||||
uint8_t *bytes = (uint8_t *) begin;
|
||||
for (uintptr_t i = 0, max_i = (end_addr - begin_addr); i < max_i; ++i) {
|
||||
if (DeepState_InputIndex >= DeepState_InputSize) {
|
||||
DeepState_Abandon("Read too many symbols");
|
||||
}
|
||||
if (FLAGS_verbose_reads) {
|
||||
printf("Reading byte at %u\n", DeepState_InputIndex);
|
||||
}
|
||||
bytes[i] = DeepState_Input[DeepState_InputIndex++];
|
||||
if (bytes[i] == 0) {
|
||||
bytes[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Concretize some data in exclusive the range `[begin, end)`. */
|
||||
void *DeepState_ConcretizeData(void *begin, void *end) {
|
||||
return begin;
|
||||
}
|
||||
|
||||
/* Return a symbolic C string of length `len`. */
|
||||
char *DeepState_CStr(size_t len) {
|
||||
/* Assign a symbolic C string of strlen length `len`. str should include
|
||||
* storage for both `len` characters AND the null terminator. Allowed
|
||||
* is a set of chars that are allowed (ignored if null). */
|
||||
void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed) {
|
||||
if (SIZE_MAX == len) {
|
||||
DeepState_Abandon("Can't create an SIZE_MAX-length string.");
|
||||
}
|
||||
if (NULL == str) {
|
||||
DeepState_Abandon("Attempted to populate null pointer.");
|
||||
}
|
||||
if (len) {
|
||||
if (!allowed) {
|
||||
DeepState_SymbolizeDataNoNull(str, &(str[len]));
|
||||
} else {
|
||||
uint32_t allowed_size = strlen(allowed);
|
||||
for (int i = 0; i < len; i++) {
|
||||
str[i] = allowed[DeepState_UIntInRange(0, allowed_size-1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
str[len] = '\0';
|
||||
}
|
||||
|
||||
/* Return a symbolic C string of strlen `len`. */
|
||||
char *DeepState_CStr_C(size_t len, const char* allowed) {
|
||||
if (SIZE_MAX == len) {
|
||||
DeepState_Abandon("Can't create an SIZE_MAX-length string");
|
||||
}
|
||||
@@ -181,17 +236,35 @@ char *DeepState_CStr(size_t len) {
|
||||
if (NULL == str) {
|
||||
DeepState_Abandon("Can't allocate memory");
|
||||
}
|
||||
DeepState_GeneratedStrings[DeepState_GeneratedStringsIndex++] = str;
|
||||
if (len) {
|
||||
DeepState_SymbolizeData(str, &(str[len - 1]));
|
||||
if (!allowed) {
|
||||
DeepState_SymbolizeDataNoNull(str, &(str[len]));
|
||||
} else {
|
||||
uint32_t allowed_size = strlen(allowed);
|
||||
for (int i = 0; i < len; i++) {
|
||||
str[i] = allowed[DeepState_UIntInRange(0, allowed_size-1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
str[len] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Symbolize a C string */
|
||||
void DeepState_SymbolizeCStr(char *begin) {
|
||||
/* Symbolize a C string; keeps the null terminator where it was. */
|
||||
void DeepState_SymbolizeCStr_C(char *begin, const char* allowed) {
|
||||
if (begin && begin[0]) {
|
||||
DeepState_SymbolizeData(begin, begin + strlen(begin));
|
||||
if (!allowed) {
|
||||
DeepState_SymbolizeDataNoNull(begin, begin + strlen(begin));
|
||||
} else {
|
||||
uint32_t allowed_size = strlen(allowed);
|
||||
uint8_t *bytes = (uint8_t *) begin;
|
||||
uintptr_t begin_addr = (uintptr_t) begin;
|
||||
uintptr_t end_addr = (uintptr_t) (begin + strlen(begin));
|
||||
for (uintptr_t i = 0, max_i = (end_addr - begin_addr); i < max_i; ++i) {
|
||||
bytes[i] = allowed[DeepState_UIntInRange(0, allowed_size-1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +390,14 @@ int32_t DeepState_MaxInt(int32_t v) {
|
||||
0x80000000U);
|
||||
}
|
||||
|
||||
/* Function to clean up generated strings, and any other DeepState-managed data. */
|
||||
extern void DeepState_CleanUp() {
|
||||
for (int i = 0; i < DeepState_GeneratedStringsIndex; i++) {
|
||||
free(DeepState_GeneratedStrings[i]);
|
||||
}
|
||||
DeepState_GeneratedStringsIndex = 0;
|
||||
}
|
||||
|
||||
void _DeepState_Assume(int expr, const char *expr_str, const char *file,
|
||||
unsigned line) {
|
||||
if (!expr) {
|
||||
@@ -435,6 +516,7 @@ void DrMemFuzzFunc(volatile uint8_t *buff, size_t size) {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
test->test_func();
|
||||
DeepState_CleanUp();
|
||||
DeepState_Pass();
|
||||
|
||||
#if defined(__cplusplus) && defined(__cpp_exceptions)
|
||||
@@ -785,6 +867,7 @@ extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
DeepState_Begin(test);
|
||||
|
||||
enum DeepState_TestRunResult result = DeepState_RunTestNoFork(test);
|
||||
DeepState_CleanUp();
|
||||
|
||||
const char* abort_check = getenv("LIBFUZZER_ABORT_ON_FAIL");
|
||||
if (abort_check != NULL) {
|
||||
|
||||
Reference in New Issue
Block a user