@@ -32,6 +32,11 @@ class Symbolic {
3232 Symbolic () {}
3333 virtual ~Symbolic () = default ; // Make Symbolic polymorphic
3434 virtual int size () = 0;
35+ virtual std::optional<z3::expr> z3_expr () { return _z3_expr; }
36+ virtual void update_z3_expr (z3::expr expr) { _z3_expr = expr; }
37+
38+ private:
39+ std::optional<z3::expr> _z3_expr;
3540};
3641
3742static int max_id = 0 ;
@@ -91,7 +96,6 @@ static std::shared_ptr<SmallBV> ZeroByte =
9196
9297struct SymVal {
9398 std::shared_ptr<Symbolic> symptr;
94- std::shared_ptr<z3::expr> z3_expr;
9599
96100 SymVal () : symptr(ZERO) {}
97101 SymVal (std::shared_ptr<Symbolic> symptr) : symptr(symptr) {}
@@ -147,20 +151,34 @@ struct SymExtract : Symbolic {
147151 SymVal value;
148152 int high;
149153 int low;
154+ int size_cache = -1 ;
150155
151156 SymExtract (SymVal value, int high, int low)
152157 : value(value), high(high), low(low) {}
153- int size () override { return 1 + value.size (); }
158+ int size () override {
159+ if (size_cache != -1 ) {
160+ return size_cache;
161+ }
162+ size_cache = 1 + value.size ();
163+ return size_cache;
164+ }
154165};
155166
156167struct SymBinary : Symbolic {
157168 Operation op;
158169 SymVal lhs;
159170 SymVal rhs;
171+ int size_cache = -1 ;
160172
161173 SymBinary (Operation op, SymVal lhs, SymVal rhs)
162174 : op(op), lhs(lhs), rhs(rhs) {}
163- int size () override { return 1 + lhs.size () + rhs.size (); }
175+ int size () override {
176+ if (size_cache != -1 ) {
177+ return size_cache;
178+ }
179+ size_cache = 1 + lhs.size () + rhs.size ();
180+ return size_cache;
181+ }
164182};
165183
166184inline SymVal SymVal::add (const SymVal &other) const {
@@ -517,6 +535,8 @@ class Snapshot_t {
517535 SymMemory_t get_memory () const { return memory; }
518536
519537 std::monostate resume_execution (NodeBox *node) const ;
538+ std::monostate resume_execution_by_model (NodeBox *node,
539+ z3::model &model) const ;
520540
521541 static int cost_of_snapshot ();
522542
@@ -527,6 +547,7 @@ class Snapshot_t {
527547 // The continuation at the snapshot point
528548 Cont_t cont;
529549 MCont_t mcont;
550+ void restore_states_to_global () const ;
530551};
531552
532553static SymFrames_t SymFrames;
@@ -899,7 +920,10 @@ inline int Snapshot_t::cost_of_snapshot() {
899920 auto cost_of_stack_copy = SymStack.cost_of_copy ();
900921 auto cost_of_frame_copy = SymFrames.cost_of_copy ();
901922 auto cost_of_memory_copy = SymMemory.cost_of_copy ();
902- return 5.336 *
923+ // The speed ratio between symbolic expression instantiation and WebAssembly
924+ // instruction execution, given by benchmark results
925+ auto ratio = 5.336 ;
926+ return ratio *
903927 (cost_of_stack_copy + cost_of_frame_copy + cost_of_memory_copy);
904928}
905929
@@ -968,22 +992,16 @@ class ExploreTree_t {
968992
969993 bool worth_to_create_snapshot () {
970994 if (!ENABLE_COST_MODEL) {
995+ // If we are not using cost model, always create snapshot
971996 return REUSE_SNAPSHOT;
972997 }
973998 // find out the best way to reach the current position via our cost model
974999 auto snapshot_cost = Snapshot_t::cost_of_snapshot ();
975- int reach_parent_cost = 0 ;
976- if (cursor->parent ) {
977- reach_parent_cost = cursor->parent ->min_cost_of_reaching_here ();
978- } else {
979- reach_parent_cost = 0 ;
1000+ int re_execution_cost = cursor->instr_cost ;
1001+ if (snapshot_cost <= re_execution_cost) {
1002+ GENSYM_INFO (" Snapshot is worth to create" );
9801003 }
981- auto parent_cost =
982- cursor->parent ? cursor->parent ->min_cost_of_reaching_here () : 0 ;
983- auto exec_from_parent_cost = reach_parent_cost + cursor->instr_cost ;
984- GENSYM_INFO (" The score of snapshot tendency: " +
985- std::to_string (exec_from_parent_cost - snapshot_cost));
986- return snapshot_cost <= exec_from_parent_cost;
1004+ return snapshot_cost <= re_execution_cost;
9871005 }
9881006
9891007 std::monostate moveCursor (bool branch, Control control) {
@@ -994,7 +1012,9 @@ class ExploreTree_t {
9941012 if_else_node != nullptr &&
9951013 " Can't move cursor when the branch node is not initialized correctly!" );
9961014 int cost_from_parent = CostManager.dump_instr_cost ();
997- cursor->instr_cost = cost_from_parent;
1015+ int cost_from_root =
1016+ cost_from_parent + (cursor->parent ? cursor->parent ->instr_cost : 0 );
1017+ cursor->instr_cost = cost_from_root;
9981018 if (branch) {
9991019 true_branch_cov_map[if_else_node->id ] = true ;
10001020 if (worth_to_create_snapshot ()) {
@@ -1026,7 +1046,9 @@ class ExploreTree_t {
10261046 if_else_node != nullptr &&
10271047 " Can't move cursor when the branch node is not initialized correctly!" );
10281048 int cost_from_parent = CostManager.dump_instr_cost ();
1029- cursor->instr_cost = cost_from_parent;
1049+ int cost_from_root =
1050+ cost_from_parent + (cursor->parent ? cursor->parent ->instr_cost : 0 );
1051+ cursor->instr_cost = cost_from_root;
10301052 if (branch) {
10311053 true_branch_cov_map[if_else_node->id ] = true ;
10321054 if_else_node->false_branch ->fillNotToExploreNode ();
@@ -1343,6 +1365,8 @@ static EvalRes eval_sym_expr(const SymVal &sym, SymEnv_t &sym_env) {
13431365 throw std::runtime_error (" Not supported symbolic expression" );
13441366}
13451367
1368+ inline EvalRes eval_sym_expr_by_model (const SymVal &sym, z3::model &model);
1369+
13461370static void resume_conc_stack (const SymStack_t &sym_stack, Stack_t &stack,
13471371 SymEnv_t &sym_env) {
13481372 stack.resize (sym_stack.size ());
@@ -1354,8 +1378,21 @@ static void resume_conc_stack(const SymStack_t &sym_stack, Stack_t &stack,
13541378 }
13551379}
13561380
1381+ static void resume_conc_stack_by_model (const SymStack_t &sym_stack,
1382+ Stack_t &stack, z3::model &model) {
1383+ GENSYM_INFO (" Restoring concrete stack from symbolic stack" );
1384+ stack.resize (sym_stack.size ());
1385+ for (size_t i = 0 ; i < sym_stack.size (); ++i) {
1386+ auto sym = sym_stack[i];
1387+ auto res = eval_sym_expr_by_model (sym, model);
1388+ auto conc = res.value ;
1389+ stack.set_from_front (i, conc);
1390+ }
1391+ }
1392+
13571393static void resume_conc_frames (const SymFrames_t &sym_frame, Frames_t &frames,
13581394 SymEnv_t &sym_env) {
1395+ GENSYM_INFO (" Restoring concrete frames from symbolic frames" );
13591396 frames.resize (sym_frame.size ());
13601397 for (size_t i = 0 ; i < sym_frame.size (); ++i) {
13611398 auto sym = sym_frame[i];
@@ -1366,8 +1403,22 @@ static void resume_conc_frames(const SymFrames_t &sym_frame, Frames_t &frames,
13661403 }
13671404}
13681405
1406+ static void resume_conc_frames_by_model (const SymFrames_t &sym_frame,
1407+ Frames_t &frames, z3::model &model) {
1408+ GENSYM_INFO (" Restoring concrete frames from symbolic frames" );
1409+ frames.resize (sym_frame.size ());
1410+ for (size_t i = 0 ; i < sym_frame.size (); ++i) {
1411+ auto sym = sym_frame[i];
1412+ assert (sym.symptr != nullptr );
1413+ auto res = eval_sym_expr_by_model (sym, model);
1414+ auto conc = res.value ;
1415+ frames.set_from_front (i, conc);
1416+ }
1417+ }
1418+
13691419static void resume_conc_memory (const SymMemory_t &sym_memory, Memory_t &memory,
13701420 SymEnv_t &sym_env) {
1421+ GENSYM_INFO (" Restoring concrete memory from symbolic memory" );
13711422 memory.reset ();
13721423 for (const auto &pair : sym_memory.memory ) {
13731424 int32_t addr = pair.first ;
@@ -1380,6 +1431,21 @@ static void resume_conc_memory(const SymMemory_t &sym_memory, Memory_t &memory,
13801431 }
13811432}
13821433
1434+ static void resume_conc_memory_by_model (const SymMemory_t &sym_memory,
1435+ Memory_t &memory, z3::model &model) {
1436+ GENSYM_INFO (" Restoring concrete memory from symbolic memory" );
1437+ memory.reset ();
1438+ for (const auto &pair : sym_memory.memory ) {
1439+ int32_t addr = pair.first ;
1440+ SymVal sym = pair.second ;
1441+ assert (sym.symptr != nullptr );
1442+ auto res = eval_sym_expr_by_model (sym, model);
1443+ auto conc = res.value ;
1444+ assert (res.width == 8 && " Memory should only store bytes" );
1445+ memory.store_byte (addr, conc.value & 0xFF );
1446+ }
1447+ }
1448+
13831449static void resume_conc_states (const SymStack_t &sym_stack,
13841450 const SymFrames_t &sym_frame,
13851451 const SymMemory_t &sym_memory, Stack_t &stack,
@@ -1390,33 +1456,51 @@ static void resume_conc_states(const SymStack_t &sym_stack,
13901456 resume_conc_memory (sym_memory, memory, sym_env);
13911457}
13921458
1393- inline std::monostate Snapshot_t::resume_execution (NodeBox *node) const {
1394- // Reset explore tree's cursor
1395- ExploreTree.set_cursor (node);
1459+ static void resume_conc_states_by_model (const SymStack_t &sym_stack,
1460+ const SymFrames_t &sym_frame,
1461+ const SymMemory_t &sym_memory,
1462+ Stack_t &stack, Frames_t &frames,
1463+ Memory_t &memory, z3::model &model) {
1464+ resume_conc_stack_by_model (sym_stack, stack, model);
1465+ resume_conc_frames_by_model (sym_frame, frames, model);
1466+ resume_conc_memory_by_model (sym_memory, memory, model);
1467+ }
13961468
1469+ inline void Snapshot_t::restore_states_to_global () const {
13971470 // Restore the symbolic state from the snapshot
13981471 GENSYM_INFO (" Reusing symbolic state from snapshot" );
13991472 SymStack = stack;
14001473 SymFrames = frames;
14011474 SymMemory = memory;
1475+ }
1476+
1477+ inline std::monostate
1478+ Snapshot_t::resume_execution_by_model (NodeBox *node, z3::model &model) const {
1479+ // Reset explore tree's cursor and restore symbolic states
1480+ ExploreTree.set_cursor (node);
1481+ restore_states_to_global ();
1482+
14021483 {
14031484 auto timer = ManagedTimer (TimeProfileKind::RESUME_SNAPSHOT);
14041485 // Restore the concrete states from the symbolic states
1405- resume_conc_states (stack, frames, memory, Stack, Frames, Memory, SymEnv);
1486+ resume_conc_states_by_model (stack, frames, memory, Stack, Frames, Memory,
1487+ model);
14061488 }
1407- int sym_size = 0 ;
1489+ // Resume execution from the continuation
1490+ auto timer = ManagedTimer (TimeProfileKind::INSTR);
1491+ return cont (mcont);
1492+ }
1493+
1494+ [[deprecated]]
1495+ inline std::monostate Snapshot_t::resume_execution (NodeBox *node) const {
1496+ // Reset explore tree's cursor and restore symbolic states
1497+ ExploreTree.set_cursor (node);
1498+ restore_states_to_global ();
14081499 {
1409- auto timer = ManagedTimer (TimeProfileKind::COUNT_SYM_SIZE);
1410- for (size_t i = 0 ; i < stack.size (); ++i) {
1411- sym_size += stack[i].size ();
1412- }
1413- for (size_t i = 0 ; i < frames.size (); ++i) {
1414- sym_size += frames[i].size ();
1415- }
1500+ auto timer = ManagedTimer (TimeProfileKind::RESUME_SNAPSHOT);
1501+ // Restore the concrete states from the symbolic states
1502+ resume_conc_states (stack, frames, memory, Stack, Frames, Memory, SymEnv);
14161503 }
1417- std::cout << " [Info] Resumed symbolic execution from snapshot, total "
1418- " symbolic expression and frame size: "
1419- << sym_size << std::endl;
14201504
14211505 // Resume execution from the continuation
14221506 auto timer = ManagedTimer (TimeProfileKind::INSTR);
0 commit comments