Skip to content

Commit 1bdb7da

Browse files
introduce a SnapshotNode, which currently behaves same as UnexploredNode
1 parent b57929a commit 1bdb7da

File tree

3 files changed

+41
-7
lines changed

3 files changed

+41
-7
lines changed

headers/wasm/concolic_driver.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ class ManagedConcolicCleanup {
3838
};
3939

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

4545
auto unexplored = ExploreTree.pick_unexplored();

headers/wasm/symbolic_rt.hpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ struct NodeBox {
273273
std::monostate fillFinishedNode();
274274
std::monostate fillFailedNode();
275275
std::monostate fillUnreachableNode();
276-
276+
std::monostate fillSnapshotNode();
277+
bool isUnexplored() const;
277278
std::vector<SymVal> collect_path_conds();
278279
};
279280

@@ -384,6 +385,22 @@ struct UnExploredNode : Node {
384385
}
385386
};
386387

388+
struct SnapshotNode : Node {
389+
SnapshotNode() {}
390+
std::string to_string() override { return "SnapshotNode"; }
391+
392+
protected:
393+
void generate_dot(std::ostream &os, int parent_dot_id,
394+
const std::string &edge_label) override {
395+
int current_node_dot_id = current_id++;
396+
graphviz_node(os, current_node_dot_id, "Snapshot", "box", "lightblue");
397+
398+
if (parent_dot_id != -1) {
399+
graphviz_edge(os, parent_dot_id, current_node_dot_id, edge_label);
400+
}
401+
}
402+
};
403+
387404
struct Finished : Node {
388405
Finished() {}
389406
std::string to_string() override { return "FinishedNode"; }
@@ -439,7 +456,7 @@ inline NodeBox::NodeBox(NodeBox *parent)
439456

440457
inline std::monostate NodeBox::fillIfElseNode(SymVal cond) {
441458
// fill the current NodeBox with an ifelse branch node when it's unexplored
442-
if (dynamic_cast<UnExploredNode *>(node.get())) {
459+
if (this->isUnexplored()) {
443460
node = std::make_unique<IfElseNode>(cond, this);
444461
}
445462
assert(
@@ -448,8 +465,15 @@ inline std::monostate NodeBox::fillIfElseNode(SymVal cond) {
448465
return std::monostate();
449466
}
450467

468+
inline std::monostate NodeBox::fillSnapshotNode() {
469+
if (this->isUnexplored()) {
470+
node = std::make_unique<SnapshotNode>();
471+
}
472+
return std::monostate();
473+
}
474+
451475
inline std::monostate NodeBox::fillFinishedNode() {
452-
if (dynamic_cast<UnExploredNode *>(node.get())) {
476+
if (this->isUnexplored()) {
453477
node = std::make_unique<Finished>();
454478
} else {
455479
assert(dynamic_cast<Finished *>(node.get()) != nullptr);
@@ -458,7 +482,7 @@ inline std::monostate NodeBox::fillFinishedNode() {
458482
}
459483

460484
inline std::monostate NodeBox::fillFailedNode() {
461-
if (dynamic_cast<UnExploredNode *>(node.get())) {
485+
if (this->isUnexplored()) {
462486
node = std::make_unique<Failed>();
463487
} else {
464488
assert(dynamic_cast<Failed *>(node.get()) != nullptr);
@@ -467,14 +491,19 @@ inline std::monostate NodeBox::fillFailedNode() {
467491
}
468492

469493
inline std::monostate NodeBox::fillUnreachableNode() {
470-
if (dynamic_cast<UnExploredNode *>(node.get())) {
494+
if (this->isUnexplored()) {
471495
node = std::make_unique<Unreachable>();
472496
} else {
473497
assert(dynamic_cast<Unreachable *>(node.get()) != nullptr);
474498
}
475499
return std::monostate();
476500
}
477501

502+
inline bool NodeBox::isUnexplored() const {
503+
return dynamic_cast<UnExploredNode *>(node.get()) != nullptr ||
504+
dynamic_cast<SnapshotNode *>(node.get()) != nullptr;
505+
}
506+
478507
inline std::vector<SymVal> NodeBox::collect_path_conds() {
479508
auto box = this;
480509
auto result = std::vector<SymVal>();
@@ -554,8 +583,10 @@ class ExploreTree_t {
554583
if_else_node != nullptr &&
555584
"Can't move cursor when the branch node is not initialized correctly!");
556585
if (branch) {
586+
if_else_node->false_branch->fillSnapshotNode();
557587
cursor = if_else_node->true_branch.get();
558588
} else {
589+
if_else_node->true_branch->fillSnapshotNode();
559590
cursor = if_else_node->false_branch.get();
560591
}
561592

@@ -599,7 +630,7 @@ class ExploreTree_t {
599630

600631
private:
601632
NodeBox *pick_unexplored_of(NodeBox *node) {
602-
if (dynamic_cast<UnExploredNode *>(node->node.get()) != nullptr) {
633+
if (node->isUnexplored()) {
603634
return node;
604635
}
605636
auto if_else_node = dynamic_cast<IfElseNode *>(node->node.get());

src/main/scala/wasm/StagedConcolicMiniWasm.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,9 @@ trait StagedWasmEvaluator extends SAIOps {
404404
val cond = (label - toStagedNum(I32V(idx))).isZero()
405405
val condSym = (labelSym - toStagedSymbolicNum(I32V(idx))).isZero()
406406
ExploreTree.fillWithIfElse(condSym.s)
407+
// When moving the cursor to a branch, we mark another branch as
408+
// snapshotNode (this is done by moveCursor's runtime implementation)
409+
// TODO: store snapshot into this snapshot node
407410
if (cond.toInt != 0) {
408411
ExploreTree.moveCursor(true)
409412
trail(choices.head)(newCtx)(mkont)

0 commit comments

Comments
 (0)