Skip to content

Commit 9ab162f

Browse files
fix: add an unreachable node & use GENSYM_ASSERT
1 parent 9a9988c commit 9ab162f

File tree

3 files changed

+97
-49
lines changed

3 files changed

+97
-49
lines changed

headers/wasm/concolic_driver.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,22 @@ class ManagedConcolicCleanup {
3737
inline void ConcolicDriver::run() {
3838
ManagedConcolicCleanup cleanup{*this};
3939
while (true) {
40-
auto cond = ExploreTree.get_unexplored_conditions();
4140
ExploreTree.reset_cursor();
4241

43-
if (!cond.has_value()) {
44-
std::cout << "No unexplored conditions found, exiting..." << std::endl;
42+
auto unexplored = ExploreTree.pick_unexplored();
43+
if (!unexplored) {
44+
std::cout << "No unexplored nodes found, exiting..." << std::endl;
4545
return;
4646
}
47-
auto new_env = solver.solve(cond.value());
47+
auto cond = unexplored->collect_path_conds();
48+
auto new_env = solver.solve(cond);
4849
if (!new_env.has_value()) {
49-
std::cout << "All unexplored paths are unreachable, exiting..."
50+
// TODO: current implementation is buggy, there could be other reachable
51+
// unexplored paths
52+
std::cout << "Found an unreachable path, marking it as unreachable..."
5053
<< std::endl;
51-
return;
54+
unexplored->fillUnreachableNode();
55+
continue;
5256
}
5357
SymEnv.update(std::move(new_env.value()));
5458
try {

headers/wasm/symbolic_rt.hpp

Lines changed: 86 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,13 @@ struct NodeBox {
193193
explicit NodeBox();
194194
std::unique_ptr<Node> node;
195195
NodeBox *parent;
196+
197+
std::monostate fillIfElseNode(SymVal cond);
198+
std::monostate fillFinishedNode();
199+
std::monostate fillFailedNode();
200+
std::monostate fillUnreachableNode();
201+
202+
std::vector<SymVal> collect_path_conds();
196203
};
197204

198205
struct Node {
@@ -334,13 +341,87 @@ struct Failed : Node {
334341
}
335342
};
336343

337-
static UnExploredNode unexplored;
344+
struct Unreachable : Node {
345+
Unreachable() {}
346+
std::string to_string() override { return "UnreachableNode"; }
347+
348+
protected:
349+
void generate_dot(std::ostream &os, int parent_dot_id,
350+
const std::string &edge_label) override {
351+
int current_node_dot_id = current_id++;
352+
graphviz_node(os, current_node_dot_id, "Unreachable", "box", "orange");
353+
354+
if (parent_dot_id != -1) {
355+
graphviz_edge(os, parent_dot_id, current_node_dot_id, edge_label);
356+
}
357+
}
358+
};
338359

339360
inline NodeBox::NodeBox()
340361
: node(std::make_unique<UnExploredNode>()),
341362
/* TODO: avoid allocation of unexplored node */
342363
parent(nullptr) {}
343364

365+
inline std::monostate NodeBox::fillIfElseNode(SymVal cond) {
366+
// fill the current NodeBox with an ifelse branch node it's unexplored
367+
if (dynamic_cast<UnExploredNode *>(node.get())) {
368+
node = std::make_unique<IfElseNode>(cond);
369+
}
370+
assert(dynamic_cast<IfElseNode *>(node.get()) != nullptr &&
371+
"Current node is not an IfElseNode, cannot fill it!");
372+
return std::monostate();
373+
}
374+
375+
inline std::monostate NodeBox::fillFinishedNode() {
376+
if (dynamic_cast<UnExploredNode *>(node.get())) {
377+
node = std::make_unique<Finished>();
378+
} else {
379+
assert(dynamic_cast<Finished *>(node.get()) != nullptr);
380+
}
381+
return std::monostate();
382+
}
383+
384+
inline std::monostate NodeBox::fillFailedNode() {
385+
if (dynamic_cast<UnExploredNode *>(node.get())) {
386+
node = std::make_unique<Failed>();
387+
} else {
388+
assert(dynamic_cast<Failed *>(node.get()) != nullptr);
389+
}
390+
return std::monostate();
391+
}
392+
393+
inline std::monostate NodeBox::fillUnreachableNode() {
394+
if (dynamic_cast<UnExploredNode *>(node.get())) {
395+
node = std::make_unique<Unreachable>();
396+
} else {
397+
assert(dynamic_cast<Unreachable *>(node.get()) != nullptr);
398+
}
399+
return std::monostate();
400+
}
401+
402+
inline std::vector<SymVal> NodeBox::collect_path_conds() {
403+
auto box = this;
404+
auto result = std::vector<SymVal>();
405+
while (box->parent) {
406+
auto parent = box->parent;
407+
auto if_else_node = dynamic_cast<IfElseNode *>(parent->node.get());
408+
if (if_else_node) {
409+
if (if_else_node->true_branch.get() == box) {
410+
// If the current box is the true branch, add the condition
411+
result.push_back(if_else_node->cond);
412+
} else if (if_else_node->false_branch.get() == box) {
413+
// If the current box is the false branch, add the negated condition
414+
result.push_back(if_else_node->cond.negate());
415+
} else {
416+
throw std::runtime_error("Unexpected node structure in explore tree");
417+
}
418+
}
419+
// Move to parent
420+
box = box->parent;
421+
}
422+
return result;
423+
}
424+
344425
class ExploreTree_t {
345426
public:
346427
explicit ExploreTree_t()
@@ -351,32 +432,12 @@ class ExploreTree_t {
351432
cursor = root.get();
352433
}
353434

354-
std::monostate fillFinishedNode() {
355-
if (dynamic_cast<UnExploredNode *>(cursor->node.get())) {
356-
cursor->node = std::make_unique<Finished>();
357-
} else {
358-
assert(dynamic_cast<Finished *>(cursor->node.get()) != nullptr);
359-
}
360-
return std::monostate{};
361-
}
435+
std::monostate fillFinishedNode() { return cursor->fillFinishedNode(); }
362436

363-
std::monostate fillFailedNode() {
364-
if (dynamic_cast<UnExploredNode *>(cursor->node.get())) {
365-
cursor->node = std::make_unique<Failed>();
366-
} else {
367-
assert(dynamic_cast<Failed *>(cursor->node.get()) != nullptr);
368-
}
369-
return std::monostate{};
370-
}
437+
std::monostate fillFailedNode() { return cursor->fillFailedNode(); }
371438

372439
std::monostate fillIfElseNode(SymVal cond) {
373-
// fill the current NodeBox with an ifelse branch node it's unexplored
374-
if (dynamic_cast<UnExploredNode *>(cursor->node.get())) {
375-
cursor->node = std::make_unique<IfElseNode>(cond);
376-
}
377-
assert(dynamic_cast<IfElseNode *>(cursor->node.get()) != nullptr &&
378-
"Current node is not an IfElseNode, cannot fill it!");
379-
return std::monostate();
440+
return cursor->fillIfElseNode(cond);
380441
}
381442

382443
std::monostate moveCursor(bool branch) {
@@ -419,24 +480,7 @@ class ExploreTree_t {
419480
if (!box) {
420481
return std::nullopt;
421482
}
422-
while (box->parent) {
423-
auto parent = box->parent;
424-
auto if_else_node = dynamic_cast<IfElseNode *>(parent->node.get());
425-
if (if_else_node) {
426-
if (if_else_node->true_branch.get() == box) {
427-
// If the current box is the true branch, add the condition
428-
result.push_back(if_else_node->cond);
429-
} else if (if_else_node->false_branch.get() == box) {
430-
// If the current box is the false branch, add the negated condition
431-
result.push_back(if_else_node->cond.negate());
432-
} else {
433-
throw std::runtime_error("Unexpected node structure in explore tree");
434-
}
435-
}
436-
// Move to parent
437-
box = box->parent;
438-
}
439-
return result;
483+
return box->collect_path_conds();
440484
}
441485

442486
NodeBox *pick_unexplored() {

src/main/scala/wasm/StagedConcolicMiniWasm.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ trait StagedWasmCppGen extends CGenBase with CppSAICodeGenBase {
982982
case Node(_, "sym-env-read", List(sym), _) =>
983983
emit("SymEnv.read("); shallow(sym); emit(")")
984984
case Node(_, "assert-true", List(cond), _) =>
985-
emit("assert("); shallow(cond); emit(")")
985+
emit("GENSYM_ASSERT("); shallow(cond); emit(")")
986986
case Node(_, "tree-fill-if-else", List(s), _) =>
987987
emit("ExploreTree.fillIfElseNode("); shallow(s); emit(")")
988988
case Node(_, "tree-fill-finished", List(), _) =>

0 commit comments

Comments
 (0)