Skip to content

Commit 8a40d30

Browse files
work list algorithm for exploration
1 parent 75b6347 commit 8a40d30

File tree

2 files changed

+52
-23
lines changed

2 files changed

+52
-23
lines changed

headers/wasm/concolic_driver.hpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class ConcolicDriver {
4242
Solver solver;
4343
std::function<void()> entrypoint;
4444
std::optional<std::string> tree_file;
45+
std::vector<NodeBox *> work_list;
4546
};
4647

4748
class ManagedConcolicCleanup {
@@ -64,19 +65,39 @@ class ManagedConcolicCleanup {
6465
static std::monostate reset_stacks();
6566

6667
inline void ConcolicDriver::main_exploration_loop() {
67-
while (true) {
68+
69+
// Register a collector to ExploreTree to add new nodes to work_list
70+
ExploreTree.register_new_node_collector(
71+
[&](NodeBox *new_node) { work_list.push_back(new_node); });
72+
73+
std::set<NodeBox *> visited;
74+
75+
assert(ExploreTree.get_root()->isUnexplored() &&
76+
"Before main loop, root should be unexplored!");
77+
work_list.push_back(ExploreTree.get_root());
78+
79+
while (!work_list.empty()) {
6880
ManagedConcolicCleanup cleanup{*this};
81+
// Pick an unexplored node from the work list
82+
auto node = work_list.back();
83+
work_list.pop_back();
6984

70-
auto unexplored = ExploreTree.pick_unexplored();
71-
if (!unexplored) {
72-
GENSYM_INFO("No unexplored nodes found, exiting...");
73-
return;
85+
if (visited.find(node) != visited.end()) {
86+
continue;
87+
} else {
88+
visited.insert(node);
7489
}
75-
auto cond = unexplored->collect_path_conds();
90+
91+
if (!node->isUnexplored()) {
92+
// if it's not unexplored anymore, skip it
93+
continue;
94+
}
95+
96+
auto cond = node->collect_path_conds();
7697
auto result = solver.solve(cond);
7798
if (!result.has_value()) {
7899
GENSYM_INFO("Found an unreachable path, marking it as unreachable...");
79-
unexplored->fillUnreachableNode();
100+
node->fillUnreachableNode();
80101
continue;
81102
}
82103
auto new_env = result.value();
@@ -87,8 +108,8 @@ inline void ConcolicDriver::main_exploration_loop() {
87108
GENSYM_INFO("Now execute the program with symbolic environment: ");
88109
GENSYM_INFO(SymEnv.to_string());
89110
if (auto snapshot_node =
90-
dynamic_cast<SnapshotNode *>(unexplored->node.get())) {
91-
snapshot_node->get_snapshot().resume_execution(SymEnv, unexplored);
111+
dynamic_cast<SnapshotNode *>(node->node.get())) {
112+
snapshot_node->get_snapshot().resume_execution(SymEnv, node);
92113
} else {
93114
auto timer = ManagedTimer();
94115
reset_stacks();

headers/wasm/symbolic_rt.hpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ struct NodeBox {
420420
std::unique_ptr<Node> node;
421421
NodeBox *parent;
422422

423-
std::monostate fillIfElseNode(SymVal cond, int id);
423+
bool fillIfElseNode(SymVal cond, int id);
424424
std::monostate fillFinishedNode();
425425
std::monostate fillFailedNode();
426426
std::monostate fillUnreachableNode();
@@ -610,15 +610,16 @@ inline NodeBox::NodeBox(NodeBox *parent)
610610
/* TODO: avoid allocation of unexplored node */
611611
parent(parent) {}
612612

613-
inline std::monostate NodeBox::fillIfElseNode(SymVal cond, int id) {
613+
inline bool NodeBox::fillIfElseNode(SymVal cond, int id) {
614614
// fill the current NodeBox with an ifelse branch node when it's unexplored
615615
if (this->isUnexplored()) {
616616
node = std::make_unique<IfElseNode>(cond, this, id);
617+
return true;
617618
}
618619
assert(
619620
dynamic_cast<IfElseNode *>(node.get()) != nullptr &&
620621
"Current node is not an Unexplored nor an IfElseNode, cannot fill it!");
621-
return std::monostate();
622+
return false;
622623
}
623624

624625
inline std::monostate NodeBox::fillSnapshotNode(Snapshot_t snapshot) {
@@ -722,7 +723,12 @@ class ExploreTree_t {
722723
std::monostate fillFailedNode() { return cursor->fillFailedNode(); }
723724

724725
std::monostate fillIfElseNode(SymVal cond, int id) {
725-
return cursor->fillIfElseNode(cond, id);
726+
if (cursor->fillIfElseNode(cond, id)) {
727+
auto if_else_node = dynamic_cast<IfElseNode *>(cursor->node.get());
728+
register_new_node(if_else_node->true_branch.get());
729+
register_new_node(if_else_node->false_branch.get());
730+
}
731+
return std::monostate();
726732
}
727733

728734
std::monostate moveCursor(bool branch, Snapshot_t snapshot) {
@@ -764,16 +770,6 @@ class ExploreTree_t {
764770
return std::monostate();
765771
}
766772

767-
std::optional<std::vector<SymVal>> get_unexplored_conditions() {
768-
// Get all unexplored conditions in the tree
769-
std::vector<SymVal> result;
770-
auto box = pick_unexplored();
771-
if (!box) {
772-
return std::nullopt;
773-
}
774-
return box->collect_path_conds();
775-
}
776-
777773
NodeBox *pick_unexplored() {
778774
// Pick an unexplored node from the tree
779775
// For now, we just iterate through the tree and return the first unexplored
@@ -793,6 +789,12 @@ class ExploreTree_t {
793789
return true;
794790
}
795791

792+
NodeBox *get_root() const { return root.get(); }
793+
794+
void register_new_node_collector(std::function<void(NodeBox *)> func) {
795+
new_node_collectors.push_back(func);
796+
}
797+
796798
private:
797799
NodeBox *pick_unexplored_of(NodeBox *node) {
798800
if (node->isUnexplored()) {
@@ -808,8 +810,14 @@ class ExploreTree_t {
808810
}
809811
return nullptr; // No unexplored node found
810812
}
813+
void register_new_node(NodeBox *node) {
814+
for (auto &func : new_node_collectors) {
815+
func(node);
816+
}
817+
}
811818
std::unique_ptr<NodeBox> root;
812819
NodeBox *cursor;
820+
std::vector<std::function<void(NodeBox *)>> new_node_collectors;
813821
};
814822

815823
static ExploreTree_t ExploreTree;

0 commit comments

Comments
 (0)