Skip to content

Commit e7af779

Browse files
Support fp load & fix memory initialize & symbolic store and load (#99)
* support float point load/store (but assuming the symbolic value is concrete) * fix memory-initialize with hex escapes in data segments * load sym float & some binary operations
1 parent b81d414 commit e7af779

8 files changed

Lines changed: 161 additions & 13 deletions

File tree

headers/wasm/concrete_num.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define WASM_CONCRETE_NUM_HPP
33
#include "wasm/profile.hpp"
44
#include "wasm/utils.hpp"
5+
#include <cmath>
56
#include <cstdint>
67

78
struct Num {
@@ -877,6 +878,27 @@ struct Num {
877878
return Num(static_cast<int64_t>(r_bits));
878879
}
879880

881+
inline Num trunc_f64_to_i32_u() const {
882+
uint64_t bits = toUInt64();
883+
double value = f64_from_bits(bits);
884+
885+
if (std::isnan(value)) {
886+
throw std::runtime_error("i32.trunc_f64_u: NaN");
887+
}
888+
if (std::isinf(value)) {
889+
throw std::runtime_error("i32.trunc_f64_u: Infinity");
890+
}
891+
if (value < 0.0 || value >= 4294967296.0) {
892+
throw std::runtime_error("i32.trunc_f64_u: Out of range");
893+
}
894+
895+
double truncated = std::trunc(value);
896+
uint32_t result = static_cast<uint32_t>(truncated);
897+
Num res(static_cast<int32_t>(result));
898+
debug_print("i32.trunc_f64_u", *this, *this, res);
899+
return res;
900+
}
901+
880902
// f64.min / f64.max: follow wasm-ish semantics: if either is NaN, return
881903
// NaN (propagate)
882904
inline Num f64_min(const Num &other) const {

headers/wasm/sym_rt.hpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,39 @@ class SymMemory_t {
354354
SymVal s7 = (it != memory.end()) ? it->second : SVFactory::ZeroByte;
355355
#endif
356356

357-
return s7.concat(s6).concat(s5).concat(s4).concat(s3).concat(s2).concat(s1).concat(s0);
357+
return s7.concat(s6)
358+
.concat(s5)
359+
.concat(s4)
360+
.concat(s3)
361+
.concat(s2)
362+
.concat(s1)
363+
.concat(s0);
364+
}
365+
366+
SymVal loadSymFloat(int32_t base, int32_t offset) {
367+
// For simplicity, we treat float as concrete value for now
368+
auto symbv = loadSym(base, offset);
369+
assert(symbv.is_concrete() && "Currently only support concrete symbolic "
370+
"value for float-point values");
371+
if (auto concrete = dynamic_cast<SymConcrete *>(symbv.symptr.get())) {
372+
auto value = concrete->value;
373+
return SVFactory::make_concrete_fp(value, 32);
374+
} else {
375+
assert(false && "unreachable");
376+
}
377+
}
378+
379+
SymVal loadSymDouble(int32_t base, int32_t offset) {
380+
// For simplicity, we treat double as concrete value for now
381+
auto symbv = loadSymLong(base, offset);
382+
assert(symbv.is_concrete() && "Currently only support concrete symbolic "
383+
"value for float-point values");
384+
if (auto concrete = dynamic_cast<SymConcrete *>(symbv.symptr.get())) {
385+
auto value = concrete->value;
386+
return SVFactory::make_concrete_fp(value, 64);
387+
} else {
388+
assert(false && "unreachable");
389+
}
358390
}
359391

360392
// when loading a symval, we need to concat 4 symbolic values
@@ -396,6 +428,18 @@ class SymMemory_t {
396428
return std::monostate{};
397429
}
398430

431+
std::monostate storeSymFloat(int32_t base, int32_t offset, SymVal value) {
432+
assert(value.is_concrete() && "Currently only support concrete symbolic "
433+
"value for float-point values");
434+
return storeSym(base, offset, value);
435+
}
436+
437+
std::monostate storeSymDouble(int32_t base, int32_t offset, SymVal value) {
438+
assert(value.is_concrete() && "Currently only support concrete symbolic "
439+
"value for float-point values");
440+
return storeSymLong(base, offset, value);
441+
}
442+
399443
std::monostate storeSymByte(int32_t addr, SymVal value) {
400444
// assume the input value is 8-bit symbolic value
401445
bool exists;

headers/wasm/symbolic_decl.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,20 @@ enum BinOperation {
1010
SUB, // Subtraction
1111
MUL, // Multiplication
1212
DIV, // Division
13+
DIV_U, // Unsigned division
1314
AND, // Logical AND
1415
OR, // Logical OR
1516
EQ_BOOL, // Equal (return a boolean) TODO: remove bv version of comparison ops
1617
NEQ_BOOL, // Not equal (return a boolean)
1718
LT_BOOL, // Less than (return a boolean)
1819
LTU_BOOL, // Unsigned less than (return a boolean)
1920
LEQ_BOOL, // Less than or equal (return a boolean)
21+
LEU_BOOL, // Unsigned less than or equal (return a boolean)
2022
GT_BOOL, // Greater than (return a boolean)
2123
GTU_BOOL, // Unsigned greater than (return a boolean)
2224
GEQ_BOOL, // Greater than or equal (return a boolean)
2325
GEU_BOOL, // Unsigned greater than or equal (return a boolean)
26+
SHL, // Shift left
2427
SHR_U, // Shift right unsigned
2528
SHR_S, // Shift right signed
2629
REM_U, // Unsigned remainder
@@ -33,7 +36,7 @@ enum BinOperation {
3336
enum UnaryOperation {
3437
NOT, // bool not
3538
BOOL2BV, // bool to bitvector,
36-
EXTEND, // bitvector extension, extend i32 to i64
39+
EXTEND, // bitvector extension, extend i32 to i64
3740
};
3841

3942
enum ValueKind { KindBV, KindBool, KindFP };
@@ -145,6 +148,8 @@ struct SymBinary : public Symbolic {
145148
case SUB:
146149
case MUL:
147150
case DIV:
151+
case DIV_U:
152+
case SHL:
148153
case SHR_U:
149154
case SHR_S:
150155
case REM_U:
@@ -166,6 +171,7 @@ struct SymBinary : public Symbolic {
166171
case LT_BOOL:
167172
case LTU_BOOL:
168173
case LEQ_BOOL:
174+
case LEU_BOOL:
169175
case GT_BOOL:
170176
case GTU_BOOL:
171177
case GEQ_BOOL:

headers/wasm/symbolic_impl.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ inline z3::expr Symbolic::build_z3_expr_aux() {
7676
case LEQ_BOOL: {
7777
return left <= right;
7878
}
79+
case LEU_BOOL: {
80+
return z3::ule(left, right);
81+
}
7982
case GT_BOOL: {
8083
return left > right;
8184
}
@@ -85,6 +88,18 @@ inline z3::expr Symbolic::build_z3_expr_aux() {
8588
case GEU_BOOL: {
8689
return z3::uge(left, right);
8790
}
91+
case SHL: {
92+
if (bit_width == 32) {
93+
z3::expr shift_mask = global_z3_ctx().bv_val(0x1F, bit_width);
94+
return z3::shl(left, right & shift_mask);
95+
} else if (bit_width == 64) {
96+
z3::expr shift_mask = global_z3_ctx().bv_val(0x3F, bit_width);
97+
return z3::shl(left, right & shift_mask);
98+
} else {
99+
throw std::runtime_error("Unsupported bit width for SHL: " +
100+
std::to_string(bit_width));
101+
}
102+
}
88103
case SHR_U: {
89104
return z3::lshr(left, right);
90105
}
@@ -109,6 +124,9 @@ inline z3::expr Symbolic::build_z3_expr_aux() {
109124
case DIV: {
110125
return left / right;
111126
}
127+
case DIV_U: {
128+
return z3::udiv(left, right);
129+
}
112130
case B_AND: {
113131
return left & right;
114132
}

headers/wasm/symval_decl.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct SymVal {
2828
SymVal minus(const SymVal &other) const;
2929
SymVal mul(const SymVal &other) const;
3030
SymVal div(const SymVal &other) const;
31+
SymVal div_u(const SymVal &other) const;
3132
SymVal eq_bool(const SymVal &other) const;
3233
SymVal neq_bool(const SymVal &other) const;
3334
SymVal land(const SymVal &other) const;
@@ -37,10 +38,12 @@ struct SymVal {
3738
SymVal lt(const SymVal &other) const;
3839
SymVal ltu(const SymVal &other) const;
3940
SymVal le(const SymVal &other) const;
41+
SymVal leu(const SymVal &other) const;
4042
SymVal gt(const SymVal &other) const;
4143
SymVal gtu(const SymVal &other) const;
4244
SymVal ge(const SymVal &other) const;
4345
SymVal geu(const SymVal &other) const;
46+
SymVal shl(const SymVal &other) const;
4447
SymVal shr_u(const SymVal &other) const;
4548
SymVal shr_s(const SymVal &other) const;
4649
SymVal bv_negate() const;
@@ -83,4 +86,10 @@ template <typename... Args> inline bool allConcrete(const Args &...args) {
8386

8487
inline SymVal Concrete(Num num, int width);
8588

89+
[[noreturn]] inline SymVal debug_unreachable(const char* msg) {
90+
std::cerr << "unreachable: " << msg << '\n';
91+
assert(false && "unreachable reached");
92+
std::abort();
93+
}
94+
8695
#endif // WASM_SYMVAL_HPP

headers/wasm/symval_factory.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,12 @@ inline SymVal make_binary(BinOperation op, const SymVal &lhs,
365365
if (lhs_width == 64 && rhs_width == 64)
366366
return make_eval_bool(lhs_value.i64_lt_u(rhs_value));
367367
break;
368+
case LEU_BOOL:
369+
if (lhs_width == 32 && rhs_width == 32)
370+
return make_eval_bool(lhs_value.i32_le_u(rhs_value));
371+
if (lhs_width == 64 && rhs_width == 64)
372+
return make_eval_bool(lhs_value.i64_le_u(rhs_value));
373+
break;
368374
case GTU_BOOL:
369375
if (lhs_width == 32 && rhs_width == 32)
370376
return make_eval_bool(lhs_value.i32_gt_u(rhs_value));

headers/wasm/symval_impl.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ inline SymVal SymVal::div(const SymVal &other) const {
2121
return SVFactory::make_binary(DIV, *this, other);
2222
}
2323

24+
inline SymVal SymVal::div_u(const SymVal &other) const {
25+
return SVFactory::make_binary(DIV_U, *this, other);
26+
}
27+
2428
inline SymVal SymVal::land(const SymVal &other) const {
2529
return SVFactory::make_binary(AND, *this, other);
2630
}
@@ -70,6 +74,10 @@ inline SymVal SymVal::le(const SymVal &other) const {
7074
return SVFactory::make_binary(LEQ_BOOL, *this, other);
7175
}
7276

77+
inline SymVal SymVal::leu(const SymVal &other) const {
78+
return SVFactory::make_binary(LEU_BOOL, *this, other);
79+
}
80+
7381
inline SymVal SymVal::gt(const SymVal &other) const {
7482
return SVFactory::make_binary(GT_BOOL, *this, other);
7583
}
@@ -86,6 +94,10 @@ inline SymVal SymVal::geu(const SymVal &other) const {
8694
return SVFactory::make_binary(GEU_BOOL, *this, other);
8795
}
8896

97+
inline SymVal SymVal::shl(const SymVal &other) const {
98+
return SVFactory::make_binary(SHL, *this, other);
99+
}
100+
89101
inline SymVal SymVal::shr_u(const SymVal &other) const {
90102
return SVFactory::make_binary(SHR_U, *this, other);
91103
}

0 commit comments

Comments
 (0)