summaryrefslogtreecommitdiff
path: root/src/wasm-validator.h
blob: 4daf9a4a7e0de7c888bfcee2aa61bc65b9bdb82e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

//
// Simple WebAssembly module validator.
//

#include "wasm.h"

namespace wasm {

struct WasmValidator : public WasmWalker {
  bool valid;

public:
  bool validate(Module& module) {
    valid = true;
    startWalk(&module);
    return valid;
  }

  // visitors

  void visitLoop(Loop *curr) override {
    if (curr->in.is()) {
      // the "in" label has a none type, since no one can receive its value. make sure no one breaks to it with a value.
      struct ChildChecker : public WasmWalker {
        Name in;
        bool valid = true;

        ChildChecker(Name in) : in(in) {}

        void visitBreak(Break *curr) override {
          if (curr->name == in && curr->value) {
            valid = false;
          }
        }
      };
      ChildChecker childChecker(curr->in);
      childChecker.walk(curr->body);
      shouldBeTrue(childChecker.valid);
    }
  }
  void visitSetLocal(SetLocal *curr) override {
    shouldBeTrue(curr->type == curr->value->type);
  }
  void visitLoad(Load *curr) override {
    validateAlignment(curr->align);
  }
  void visitStore(Store *curr) override {
    validateAlignment(curr->align);
  }
  void visitSwitch(Switch *curr) override {
    std::set<Name> inTable;
    for (auto target : curr->targets) {
      if (target.is()) {
        inTable.insert(target);
      }
    }
    for (auto& c : curr->cases) {
      shouldBeFalse(c.name.is() && inTable.find(c.name) == inTable.end());
    }
    shouldBeFalse(curr->default_.is() && inTable.find(curr->default_) == inTable.end());
  }
  void visitUnary(Unary *curr) override {
    shouldBeTrue(curr->value->type == curr->type);
  }

  void visitFunction(Function *curr) override {
    shouldBeTrue(curr->result == curr->body->type);
  }
  void visitMemory(Memory *curr) override {
    shouldBeFalse(curr->initial > curr->max);
    size_t top = 0;
    for (auto segment : curr->segments) {
      shouldBeFalse(segment.offset < top);
      top = segment.offset + segment.size;
    }
    shouldBeFalse(top > curr->initial);
  }
  void visitModule(Module *curr) override {
    for (auto& exp : curr->exports) {
      Name name = exp->name;
      bool found = false;
      for (auto& func : curr->functions) {
        if (func->name == name) {
          found = true;
          break;
        }
      }
      shouldBeTrue(found);
    }
  }

private:
  // helpers

  void shouldBeTrue(bool result) {
    if (!result) valid = false;
  }
  void shouldBeFalse(bool result) {
    if (result) valid = false;
  }

  void validateAlignment(size_t align) {
    switch (align) {
      case 1:
      case 2:
      case 4:
      case 8: break;
      default:{
        valid = false;
        break;
      }
    }
  }
};

} // namespace wasm