Changed how the logging works to log to a static buffer, then the hooks pull info out from there.

This commit is contained in:
Peter Goodman 2017-10-30 14:16:02 -04:00
parent e4f4cfe0db
commit 3702bfcb81
6 changed files with 86 additions and 44 deletions

View File

@ -174,19 +174,20 @@ LEVEL_TO_LOGGER = {
}
def hook_Log(state, level, begin_ea, end_ea):
def hook_Log(state, level, begin_ea):
"""Implements McTest_Log, which lets Manticore intercept and handle the
printing of log messages from the simulated tests."""
level = state.solve_one(level)
assert level in LEVEL_TO_LOGGER
begin_ea = state.solve_one(begin_ea)
end_ea = state.solve_one(end_ea)
assert begin_ea <= end_ea
message_bytes = []
for i in xrange(end_ea - begin_ea):
message_bytes.append(state.cpu.memory[begin_ea + i])
for i in xrange(4096):
b = state.cpu.read_int(begin_ea + i, 8)
if not issymbolic(b) and b == 0:
break
message_bytes.append(b)
state.context['log_messages'].append((level, message_bytes))
@ -209,14 +210,11 @@ def done_test(_, state, state_id, reason):
for level, message_bytes in state.context['log_messages']:
message = []
for b in message_bytes:
if issymbolic(b):
b_ord = state.solve_one(b)
state.constrain(b == b_ord)
message.append(chr(b_ord))
elif isinstance(b, (int, long)):
message.append(chr(b))
b_ord = state.solve_one(b)
if b_ord == 0:
break
else:
message.append(b)
message.append(chr(b_ord))
LEVEL_TO_LOGGER[level]("".join(message))
@ -230,8 +228,7 @@ def done_test(_, state, state_id, reason):
output = []
for i in xrange(input_length):
b = state.cpu.read_int(state.context['InputBegin'] + i, 8)
if issymbolic(b):
b = state.solve_one(b)
b = state.solve_one(b)
output.append("{:2x}".format(b))
L.info("Input: {}".format(" ".join(output)))
@ -244,7 +241,7 @@ def do_run_test(state, apis, test):
m.verbosity(1)
state = m.initial_state
messages = [(1, "Running {} from {}:{}".format(
messages = [(1, "Running {} from {}({})".format(
test.name, test.file_name, test.line_number))]
state.context['InputBegin'] = apis['InputBegin']
@ -279,6 +276,10 @@ def run_tests(args, state, apis):
pool = multiprocessing.Pool(processes=max(1, args.num_workers))
results = []
tests = find_test_cases(state, apis['LastTestInfo'])
L.info("Running {} tests across {} workers".format(
len(tests), args.num_workers))
for test in tests:
res = pool.apply_async(run_test, (state, apis, test))
results.append(res)
@ -302,7 +303,7 @@ def main():
args = parser.parse_args()
m = manticore.Manticore(sys.argv[1], sys.argv[1:])
m = manticore.Manticore(args.binary)
m.verbosity(1)
# Hack to get around current broken _get_symbol_address

View File

@ -29,7 +29,7 @@ L.setLevel(logging.INFO)
def hook_function(project, ea, cls):
"""Hook the function `name` with the SimProcedure `cls`."""
"""Hook the function `ea` with the SimProcedure `cls`."""
project.hook(ea, cls(project=project))
@ -186,16 +186,22 @@ LEVEL_TO_LOGGER = {
class Log(angr.SimProcedure):
"""Implements McTest_Log, which lets Angr intercept and handle the
printing of log messages from the simulated tests."""
def run(self, level, begin_ea, end_ea):
def run(self, level, begin_ea_):
level = self.state.solver.eval(level, cast_to=int)
assert level in LEVEL_TO_LOGGER
begin_ea = self.state.solver.eval(begin_ea, cast_to=int)
end_ea = self.state.solver.eval(end_ea, cast_to=int)
assert begin_ea <= end_ea
begin_ea = self.state.solver.eval(begin_ea_, cast_to=int)
if self.state.se.symbolic(begin_ea_):
self.state.solver.add(begin_ea_ == begin_ea)
data = []
for i in xrange(4096):
b = self.state.memory.load(begin_ea + i, size=1)
solutions = self.state.solver.eval_upto(b, 2, cast_to=int)
if 1 == len(solutions) and solutions[0] == 0:
break
data.append(b)
size = end_ea - begin_ea
data = self.state.memory.load(begin_ea, size=size)
self.state.globals['log_messages'].append((level, data))
if 3 == level:
@ -212,9 +218,15 @@ def done_test(state):
# Dump out any pending log messages reported by `McTest_Log`.
for level, message in state.globals['log_messages']:
if not isinstance(message, str):
message = state.solver.eval(message, cast_to=str)
LEVEL_TO_LOGGER[level]("".join(message))
data = []
for b in message:
if not isinstance(b, str):
b = state.solver.eval(b, cast_to=str)
if not ord(b):
break
data.append(b)
LEVEL_TO_LOGGER[level]("".join(data))
max_length = state.globals['InputEnd'] - state.globals['InputBegin']
if input_length > max_length:
@ -239,7 +251,7 @@ def do_run_test(project, test, apis, run_state):
test.ea,
base_state=run_state)
messages = [(1, "Running {} from {}:{}".format(
messages = [(1, "Running {} from {}({})".format(
test.name, test.file_name, test.line_number))]
test_state.globals['InputBegin'] = apis['InputBegin']
@ -330,6 +342,9 @@ def main():
# Find the test cases that we want to run.
tests = find_test_cases(run_state, apis['LastTestInfo'])
L.info("Running {} tests across {} workers".format(
len(tests), args.num_workers))
pool = multiprocessing.Pool(processes=max(1, args.num_workers))
results = []

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
add_executable(OutOfBoundsInt OutOfBoundsInt.c)
add_executable(OutOfBoundsInt OutOfBoundsInt.cpp)
target_link_libraries(OutOfBoundsInt mctest)
add_executable(ArithmeticProperties ArithmeticProperties.cpp)

View File

@ -14,18 +14,20 @@
* limitations under the License.
*/
#include <mctest/McTest.h>
#include <mctest/McUnit.hpp>
McTest_EntryPoint(YIsAlwaysPositive) {
TEST(BoundsCheck, YIsAlwaysPositive) {
int x = McTest_IntInRange(-10, 10);
int y = x * x;
McTest_Assert(y >= 0);
ASSERT_GE(y, 0)
<< "Found y=" << y << " was not always positive.";
}
McTest_EntryPoint(YIsAlwaysPositive_CanFail) {
int x = McTest_IntInRange(-10, 10);
int y = x * x * x;
McTest_Assert(y >= 0); /* This can fail */
TEST(BoundsCheck, YIsAlwaysPositive_CanFail) {
int x = McTest_Int();
int y = x * x; // Can overflow!
ASSERT_GE(y, 0)
<< "Found y=" << y << " was not always positive.";
}
int main(int argc, char *argv[]) {

View File

@ -269,7 +269,7 @@ static int McTest_Run(void) {
for (test = McTest_FirstTest(); test != NULL; test = test->prev) {
/* Print the test that we're going to run. */
num_buff_bytes_used = sprintf(buff, "Running: %s from %s:%u",
num_buff_bytes_used = sprintf(buff, "Running: %s from %s(%u)",
test->test_name, test->file_name,
test->line_number);
McTest_Log(McTest_LogInfo, buff, &(buff[num_buff_bytes_used]));

View File

@ -166,13 +166,15 @@ static const char *McTest_LogLevelStr(enum McTest_LogLevel level) {
}
}
/* Outputs information to a log, using a specific log level. */
void McTest_Log(enum McTest_LogLevel level, const char *begin,
const char *end) {
int str_len = (int) (end - begin);
fprintf(stderr, "%s: %.*s\n", McTest_LogLevelStr(level),
str_len, begin);
enum {
McTest_LogBufSize = 4096
};
char McTest_LogBuf[McTest_LogBufSize + 1] = {};
void _McTest_Log(enum McTest_LogLevel level, const char *message) {
fprintf(stderr, "%s: %s\n", McTest_LogLevelStr(level), message);
if (McTest_LogError == level) {
McTest_SoftFail();
@ -181,6 +183,28 @@ void McTest_Log(enum McTest_LogLevel level, const char *begin,
}
}
/* Outputs information to a log, using a specific log level. */
void McTest_Log(enum McTest_LogLevel level, const char *begin,
const char *end) {
if (end <= begin) {
return;
}
size_t size = (size_t) (end - begin);
if (size > McTest_LogBufSize) {
size = McTest_LogBufSize;
}
/* When we interpose on _McTest_Log, we are looking for the first non-symbolic
* zero byte as our end of string character, so we want to guarantee that we
* have a bunch of those */
memset(McTest_LogBuf, 0, McTest_LogBufSize);
memcpy(McTest_LogBuf, begin, size);
McTest_LogBuf[McTest_LogBufSize] = '\0';
_McTest_Log(level, McTest_LogBuf);
}
/* A McTest-specific symbol that is needed for hooking. */
struct McTest_IndexEntry {
const char * const name;
@ -193,7 +217,7 @@ const struct McTest_IndexEntry McTest_API[] = {
{"Pass", (void *) McTest_Pass},
{"Fail", (void *) McTest_Fail},
{"SoftFail", (void *) McTest_SoftFail},
{"Log", (void *) McTest_Log},
{"Log", (void *) _McTest_Log},
{"Assume", (void *) _McTest_Assume},
{"IsSymbolicUInt", (void *) McTest_IsSymbolicUInt},
{"InputBegin", (void *) &(McTest_Input[0])},