Skip to content

Commit 463871c

Browse files
snapshot reuse via continuation
more tests should be added
1 parent 64dce32 commit 463871c

File tree

5 files changed

+172
-36
lines changed

5 files changed

+172
-36
lines changed

headers/wasm/concolic_driver.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ class ManagedConcolicCleanup {
3838
};
3939

4040
inline void ConcolicDriver::run() {
41+
ExploreTree.reset_cursor();
4142
while (true) {
4243
ManagedConcolicCleanup cleanup{*this};
43-
ExploreTree.reset_cursor();
4444

4545
auto unexplored = ExploreTree.pick_unexplored();
4646
if (!unexplored) {
@@ -55,11 +55,19 @@ inline void ConcolicDriver::run() {
5555
continue;
5656
}
5757
auto new_env = result.value();
58+
59+
// update global symbolic environment from SMT solved model
5860
SymEnv.update(std::move(new_env));
5961
try {
6062
GENSYM_INFO("Now execute the program with symbolic environment: ");
6163
GENSYM_INFO(SymEnv.to_string());
62-
entrypoint();
64+
if (auto snapshot_node =
65+
dynamic_cast<SnapshotNode *>(unexplored->node.get())) {
66+
snapshot_node->get_snapshot().resume_execution(SymEnv, unexplored);
67+
} else {
68+
entrypoint();
69+
}
70+
6371
GENSYM_INFO("Execution finished successfully with symbolic environment:");
6472
GENSYM_INFO(SymEnv.to_string());
6573
} catch (...) {

headers/wasm/concrete_rt.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef WASM_CONCRETE_RT_HPP
22
#define WASM_CONCRETE_RT_HPP
33

4+
#include "wasm/utils.hpp"
45
#include <cassert>
56
#include <cstdint>
67
#include <cstdio>
@@ -120,6 +121,16 @@ class Stack_t {
120121

121122
void reset() { count = 0; }
122123

124+
void resize(int32_t new_size) {
125+
assert(new_size >= 0);
126+
count = new_size;
127+
}
128+
129+
void set_from_front(int32_t index, const Num &num) {
130+
assert(index >= 0 && index < count);
131+
stack_ptr[index] = num;
132+
}
133+
123134
private:
124135
int32_t count;
125136
Num *stack_ptr;
@@ -152,6 +163,19 @@ class Frames_t {
152163

153164
void reset() { count = 0; }
154165

166+
size_t size() const { return count; }
167+
168+
void set_from_front(int32_t index, const Num &num) {
169+
GENSYM_DBG(index);
170+
assert(index >= 0 && index < count && "Index out of bounds");
171+
stack_ptr[index] = num;
172+
}
173+
174+
void resize(int32_t new_size) {
175+
assert(new_size >= 0);
176+
count = new_size;
177+
}
178+
155179
private:
156180
int32_t count;
157181
Num *stack_ptr;

headers/wasm/controls.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
2+
#ifndef WASM_CONTROLS_HPP
3+
#define WASM_CONTROLS_HPP
4+
15
#include <functional>
6+
27
#include <variant>
38

49
using MCont_t = std::function<std::monostate(std::monostate)>;
5-
using Cont_t = std::function<std::monostate(MCont_t)>;
10+
using Cont_t = std::function<std::monostate(MCont_t)>;
11+
12+
#endif // WASM_CONTROLS_HPP

headers/wasm/symbolic_rt.hpp

Lines changed: 127 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "concrete_rt.hpp"
55
#include "controls.hpp"
6+
#include "utils.hpp"
67
#include <cassert>
78
#include <cstddef>
89
#include <cstdio>
@@ -71,6 +72,8 @@ struct SymVal {
7172
SymVal gt(const SymVal &other) const;
7273
SymVal geq(const SymVal &other) const;
7374
SymVal negate() const;
75+
76+
bool is_concrete() const;
7477
};
7578

7679
static SymVal make_symbolic(int index) {
@@ -145,6 +148,10 @@ inline SymVal SymVal::makeSymbolic() const {
145148
}
146149
}
147150

151+
inline bool SymVal::is_concrete() const {
152+
return dynamic_cast<SymConcrete *>(symptr.get()) != nullptr;
153+
}
154+
148155
class Snapshot_t;
149156

150157
class SymStack_t {
@@ -186,6 +193,8 @@ class SymStack_t {
186193

187194
size_t size() const { return stack.size(); }
188195

196+
SymVal operator[](size_t index) const { return stack[index]; }
197+
189198
private:
190199
std::vector<SymVal> stack;
191200
};
@@ -222,9 +231,17 @@ class SymFrames_t {
222231

223232
void reuse(Snapshot_t snapshot);
224233

234+
size_t size() const { return stack.size(); }
235+
236+
SymVal operator[](size_t index) const { return stack[index]; }
237+
238+
private:
225239
std::vector<SymVal> stack;
226240
};
227241

242+
struct NodeBox;
243+
struct SymEnv_t;
244+
228245
// A snapshot of the symbolic state and execution context (control)
229246
class Snapshot_t {
230247
public:
@@ -233,6 +250,8 @@ class Snapshot_t {
233250
SymStack_t get_stack() const { return stack; }
234251
SymFrames_t get_frames() const { return frames; }
235252

253+
std::monostate resume_execution(SymEnv_t &sym_env, NodeBox *node) const;
254+
236255
private:
237256
SymStack_t stack;
238257
SymFrames_t frames;
@@ -391,6 +410,7 @@ struct UnExploredNode : Node {
391410
struct SnapshotNode : Node {
392411
SnapshotNode(Snapshot_t snapshot) : snapshot(snapshot) {}
393412
std::string to_string() override { return "SnapshotNode"; }
413+
const Snapshot_t &get_snapshot() const { return snapshot; }
394414

395415
protected:
396416
void generate_dot(std::ostream &os, int parent_dot_id,
@@ -479,6 +499,7 @@ inline std::monostate NodeBox::fillSnapshotNode(Snapshot_t snapshot) {
479499
}
480500

481501
inline std::monostate NodeBox::fillFinishedNode() {
502+
GENSYM_DBG("Filling with a Finished Node");
482503
if (this->isUnexplored()) {
483504
node = std::make_unique<Finished>();
484505
} else {
@@ -491,6 +512,11 @@ inline std::monostate NodeBox::fillFailedNode() {
491512
if (this->isUnexplored()) {
492513
node = std::make_unique<Failed>();
493514
} else {
515+
if (auto if_else_node = dynamic_cast<IfElseNode *>(node.get())) {
516+
GENSYM_DBG(typeid(*if_else_node).name());
517+
} else if (auto finished_node = dynamic_cast<Finished *>(node.get())) {
518+
GENSYM_DBG(typeid(*finished_node).name());
519+
}
494520
assert(dynamic_cast<Failed *>(node.get()) != nullptr);
495521
}
496522
return std::monostate();
@@ -533,24 +559,6 @@ inline std::vector<SymVal> NodeBox::collect_path_conds() {
533559
return result;
534560
}
535561

536-
class Reuse_t {
537-
public:
538-
Reuse_t() : reuse_flag(false) {}
539-
bool is_reusing() {
540-
// we are in reuse mode and the flag is set
541-
return REUSE_MODE && reuse_flag;
542-
}
543-
544-
void turn_on_reusing() { reuse_flag = true; }
545-
546-
void turn_off_reusing() { reuse_flag = false; }
547-
548-
private:
549-
bool reuse_flag;
550-
};
551-
552-
static Reuse_t Reuse;
553-
554562
inline Snapshot_t::Snapshot_t(Cont_t cont, MCont_t mcont)
555563
: stack(SymStack), frames(SymFrames), cont(cont), mcont(mcont) {
556564
#ifdef DEBUG
@@ -564,13 +572,15 @@ class ExploreTree_t {
564572
: root(std::make_unique<NodeBox>(nullptr)), cursor(root.get()) {}
565573

566574
void reset_cursor() {
575+
GENSYM_INFO("Resetting cursor to root");
567576
// Reset the cursor to the root of the tree
568577
cursor = root.get();
569-
Reuse.turn_off_reusing();
570-
// if root cursor is a branch node, then we can reuse the snapshot inside it
571-
if (auto ite = dynamic_cast<IfElseNode *>(cursor->node.get())) {
572-
Reuse.turn_on_reusing();
573-
}
578+
}
579+
580+
void set_cursor(NodeBox *new_cursor) {
581+
GENSYM_INFO("Setting cursor to a new node");
582+
cursor = new_cursor;
583+
assert(dynamic_cast<SnapshotNode *>(cursor->node.get()) != nullptr);
574584
}
575585

576586
std::monostate fillFinishedNode() { return cursor->fillFinishedNode(); }
@@ -656,18 +666,23 @@ static ExploreTree_t ExploreTree;
656666

657667
class SymEnv_t {
658668
public:
659-
Num read(SymVal sym) {
660-
auto symbol = dynamic_cast<Symbol *>(sym.symptr.get());
661-
assert(symbol);
662-
if (symbol->get_id() >= map.size()) {
663-
map.resize(symbol->get_id() + 1);
669+
Num read(const Symbol &symbol) {
670+
if (symbol.get_id() >= map.size()) {
671+
map.resize(symbol.get_id() + 1);
664672
}
665673
#if DEBUG
666-
std::cout << "Read symbol: " << symbol->get_id()
674+
std::cout << "Read symbol: " << symbol.get_id()
667675
<< " from symbolic environment" << std::endl;
668676
std::cout << "Current symbolic environment: " << to_string() << std::endl;
669677
#endif
670-
return map[symbol->get_id()];
678+
679+
return map[symbol.get_id()];
680+
}
681+
682+
Num read(SymVal sym) {
683+
auto symbol = dynamic_cast<Symbol *>(sym.symptr.get());
684+
assert(symbol);
685+
return read(*symbol);
671686
}
672687

673688
void update(std::vector<Num> new_env) { map = std::move(new_env); }
@@ -684,10 +699,92 @@ class SymEnv_t {
684699
return result;
685700
}
686701

702+
size_t size() const { return map.size(); }
703+
687704
private:
688705
std::vector<Num> map; // The symbolic environment, a vector of Num
689706
};
690707

691708
static SymEnv_t SymEnv;
692709

710+
// TODO: reduce the re-computation of the same symbolic expression, it's better
711+
// if it can be done by the smt solver
712+
static Num eval_sym_expr(const SymVal &sym, SymEnv_t &sym_env) {
713+
if (auto concrete = dynamic_cast<SymConcrete *>(sym.symptr.get())) {
714+
return concrete->value;
715+
} else if (auto operation = dynamic_cast<SymBinary *>(sym.symptr.get())) {
716+
// If it's a operation, we need to evaluate it
717+
auto lhs = eval_sym_expr(operation->lhs, sym_env);
718+
auto rhs = eval_sym_expr(operation->rhs, sym_env);
719+
switch (operation->op) {
720+
case ADD:
721+
return lhs + rhs;
722+
case SUB:
723+
return lhs - rhs;
724+
case MUL:
725+
return lhs * rhs;
726+
case DIV:
727+
return lhs / rhs;
728+
case LT:
729+
return lhs < rhs;
730+
case LEQ:
731+
return lhs <= rhs;
732+
case GT:
733+
return lhs > rhs;
734+
case GEQ:
735+
return lhs >= rhs;
736+
default:
737+
throw std::runtime_error("Operation not supported: " +
738+
std::to_string(operation->op));
739+
}
740+
} else if (auto symbol = dynamic_cast<Symbol *>(sym.symptr.get())) {
741+
auto sym_id = symbol->get_id();
742+
GENSYM_INFO("Reading symbol: " + std::to_string(sym_id));
743+
return sym_env.read(sym);
744+
}
745+
throw std::runtime_error("Not supported symbolic expression");
746+
}
747+
748+
static void resume_conc_stack(const SymStack_t &sym_stack, Stack_t &stack,
749+
SymEnv_t &sym_env) {
750+
stack.resize(sym_stack.size());
751+
for (size_t i = 0; i < sym_stack.size(); ++i) {
752+
auto sym = sym_stack[i];
753+
auto conc = eval_sym_expr(sym, sym_env);
754+
stack.set_from_front(i, conc);
755+
}
756+
}
757+
758+
static void resume_conc_frames(const SymFrames_t &sym_frame, Frames_t &frames,
759+
SymEnv_t &sym_env) {
760+
frames.resize(sym_frame.size());
761+
for (size_t i = 0; i < sym_frame.size(); ++i) {
762+
auto sym = sym_frame[i];
763+
auto conc = eval_sym_expr(sym, sym_env);
764+
frames.set_from_front(i, conc);
765+
}
766+
}
767+
768+
static void resume_conc_states(const SymStack_t &sym_stack,
769+
const SymFrames_t &sym_frame, Stack_t &stack,
770+
Frames_t &frames, SymEnv_t &sym_env) {
771+
resume_conc_stack(sym_stack, stack, sym_env);
772+
resume_conc_frames(sym_frame, frames, sym_env);
773+
}
774+
775+
inline std::monostate Snapshot_t::resume_execution(SymEnv_t &sym_env,
776+
NodeBox *node) const {
777+
// Reset explore tree's cursor
778+
ExploreTree.set_cursor(node);
779+
780+
// Restore the symbolic state from the snapshot
781+
GENSYM_INFO("Reusing symbolic state from snapshot");
782+
SymStack = stack;
783+
SymFrames = frames;
784+
// Restore the concrete states from the symbolic states
785+
resume_conc_states(stack, frames, Stack, Frames, sym_env);
786+
// Resume execution from the continuation
787+
return cont(mcont);
788+
}
789+
693790
#endif // WASM_SYMBOLIC_RT_HPP

src/test/scala/genwasym/TestStagedConcolicEval.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ class TestStagedConcolicEval extends FunSuite {
4242
})
4343
}
4444

45-
test("ack-cpp") { testFileConcolicCpp("./benchmarks/wasm/ack.wat", Some("real_main")) }
45+
test("ack-cpp-concolic") { testFileConcolicCpp("./benchmarks/wasm/ack.wat", Some("real_main")) }
4646

47-
test("bug-finding") {
47+
test("bug-finding-concolic") {
4848
testFileConcolicCpp("./benchmarks/wasm/branch-strip-buggy.wat", Some("real_main"))
4949
}
5050

51-
test("brtable-bug-finding") {
51+
test("brtable-bug-finding-concolic") {
5252
testFileConcolicCpp("./benchmarks/wasm/staged/brtable_concolic.wat")
5353
}
5454

0 commit comments

Comments
 (0)