Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: src/wasm/decoder.h

Issue 1644023002: [wasm] Fix misaligned accesses and endianness issues in decoders. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/ast-decoder.cc ('k') | src/wasm/module-decoder.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_WASM_DECODER_H_ 5 #ifndef V8_WASM_DECODER_H_
6 #define V8_WASM_DECODER_H_ 6 #define V8_WASM_DECODER_H_
7 7
8 #include "src/base/smart-pointers.h" 8 #include "src/base/smart-pointers.h"
9 #include "src/flags.h" 9 #include "src/flags.h"
10 #include "src/signature.h" 10 #include "src/signature.h"
11 #include "src/wasm/wasm-result.h" 11 #include "src/wasm/wasm-result.h"
12 #include "src/zone-containers.h" 12 #include "src/zone-containers.h"
13 13
14 namespace v8 { 14 namespace v8 {
15 namespace internal { 15 namespace internal {
16 namespace wasm { 16 namespace wasm {
17 17
18 #if DEBUG 18 #if DEBUG
19 #define TRACE(...) \ 19 #define TRACE(...) \
20 do { \ 20 do { \
21 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 21 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
22 } while (false) 22 } while (false)
23 #else 23 #else
24 #define TRACE(...) 24 #define TRACE(...)
25 #endif 25 #endif
26 26
27 #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
28 #define UNALIGNED_ACCESS_OK 1
29 #else
30 #define UNALIGNED_ACCESS_OK 0
31 #endif
32
27 // A helper utility to decode bytes, integers, fields, varints, etc, from 33 // A helper utility to decode bytes, integers, fields, varints, etc, from
28 // a buffer of bytes. 34 // a buffer of bytes.
29 class Decoder { 35 class Decoder {
30 public: 36 public:
31 Decoder(const byte* start, const byte* end) 37 Decoder(const byte* start, const byte* end)
32 : start_(start), 38 : start_(start),
33 pc_(start), 39 pc_(start),
34 limit_(end), 40 limit_(end),
41 end_(end),
35 error_pc_(nullptr), 42 error_pc_(nullptr),
36 error_pt_(nullptr) {} 43 error_pt_(nullptr) {}
37 44
38 virtual ~Decoder() {} 45 virtual ~Decoder() {}
39 46
47 // Reads a single 16-bit unsigned integer (little endian).
48 inline uint16_t read_u16(const byte* ptr) {
49 DCHECK(ptr >= start_ && (ptr + 2) <= end_);
50 #if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
51 return *reinterpret_cast<const uint16_t*>(ptr);
52 #else
53 uint16_t b0 = ptr[0];
54 uint16_t b1 = ptr[1];
55 return (b1 << 8) | b0;
56 #endif
57 }
58
59 // Reads a single 32-bit unsigned integer (little endian).
60 inline uint32_t read_u32(const byte* ptr) {
61 DCHECK(ptr >= start_ && (ptr + 4) <= end_);
62 #if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
63 return *reinterpret_cast<const uint32_t*>(ptr);
64 #else
65 uint32_t b0 = ptr[0];
66 uint32_t b1 = ptr[1];
67 uint32_t b2 = ptr[2];
68 uint32_t b3 = ptr[3];
69 return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
70 #endif
71 }
72
73 // Reads a single 64-bit unsigned integer (little endian).
74 inline uint64_t read_u64(const byte* ptr) {
75 DCHECK(ptr >= start_ && (ptr + 8) <= end_);
76 #if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
77 return *reinterpret_cast<const uint64_t*>(ptr);
78 #else
79 uint32_t b0 = ptr[0];
80 uint32_t b1 = ptr[1];
81 uint32_t b2 = ptr[2];
82 uint32_t b3 = ptr[3];
83 uint32_t low = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
84 uint32_t b4 = ptr[4];
85 uint32_t b5 = ptr[5];
86 uint32_t b6 = ptr[6];
87 uint32_t b7 = ptr[7];
88 uint64_t high = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
89 return (high << 32) | low;
90 #endif
91 }
92
40 // Reads a 8-bit unsigned integer (byte) and advances {pc_}. 93 // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
41 uint8_t u8(const char* name = nullptr) { 94 uint8_t consume_u8(const char* name = nullptr) {
42 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 95 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
43 name ? name : "uint8_t"); 96 name ? name : "uint8_t");
44 if (checkAvailable(1)) { 97 if (checkAvailable(1)) {
45 byte val = *(pc_++); 98 byte val = *(pc_++);
46 TRACE("%02x = %d\n", val, val); 99 TRACE("%02x = %d\n", val, val);
47 return val; 100 return val;
48 } else {
49 error("expected 1 byte, but fell off end");
50 return traceOffEnd<uint8_t>();
51 } 101 }
102 return traceOffEnd<uint8_t>();
52 } 103 }
53 104
54 // Reads a 16-bit unsigned integer (little endian) and advances {pc_}. 105 // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
55 uint16_t u16(const char* name = nullptr) { 106 uint16_t consume_u16(const char* name = nullptr) {
56 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 107 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
57 name ? name : "uint16_t"); 108 name ? name : "uint16_t");
58 if (checkAvailable(2)) { 109 if (checkAvailable(2)) {
59 #ifdef V8_TARGET_LITTLE_ENDIAN 110 uint16_t val = read_u16(pc_);
60 byte b0 = pc_[0];
61 byte b1 = pc_[1];
62 #else
63 byte b1 = pc_[0];
64 byte b0 = pc_[1];
65 #endif
66 uint16_t val = static_cast<uint16_t>(b1 << 8) | b0;
67 TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val); 111 TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
68 pc_ += 2; 112 pc_ += 2;
69 return val; 113 return val;
70 } else {
71 error("expected 2 bytes, but fell off end");
72 return traceOffEnd<uint16_t>();
73 } 114 }
115 return traceOffEnd<uint16_t>();
74 } 116 }
75 117
76 // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}. 118 // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
77 uint32_t u32(const char* name = nullptr) { 119 uint32_t consume_u32(const char* name = nullptr) {
78 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 120 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
79 name ? name : "uint32_t"); 121 name ? name : "uint32_t");
80 if (checkAvailable(4)) { 122 if (checkAvailable(4)) {
81 #ifdef V8_TARGET_LITTLE_ENDIAN 123 uint32_t val = read_u32(pc_);
82 byte b0 = pc_[0];
83 byte b1 = pc_[1];
84 byte b2 = pc_[2];
85 byte b3 = pc_[3];
86 #else
87 byte b3 = pc_[0];
88 byte b2 = pc_[1];
89 byte b1 = pc_[2];
90 byte b0 = pc_[3];
91 #endif
92 uint32_t val = static_cast<uint32_t>(b3 << 24) |
93 static_cast<uint32_t>(b2 << 16) |
94 static_cast<uint32_t>(b1 << 8) | b0;
95 TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val); 124 TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val);
96 pc_ += 4; 125 pc_ += 4;
97 return val; 126 return val;
98 } else {
99 error("expected 4 bytes, but fell off end");
100 return traceOffEnd<uint32_t>();
101 } 127 }
128 return traceOffEnd<uint32_t>();
102 } 129 }
103 130
104 // Reads a LEB128 variable-length 32-bit integer and advances {pc_}. 131 // Reads a LEB128 variable-length 32-bit integer and advances {pc_}.
105 uint32_t u32v(int* length, const char* name = nullptr) { 132 uint32_t consume_u32v(int* length, const char* name = nullptr) {
106 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 133 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
107 name ? name : "varint"); 134 name ? name : "varint");
108 135
109 if (!checkAvailable(1)) { 136 if (checkAvailable(1)) {
110 error("expected at least 1 byte, but fell off end"); 137 const byte* pos = pc_;
111 return traceOffEnd<uint32_t>(); 138 const byte* end = pc_ + 5;
139 if (end > limit_) end = limit_;
140
141 uint32_t result = 0;
142 int shift = 0;
143 byte b = 0;
144 while (pc_ < end) {
145 b = *pc_++;
146 TRACE("%02x ", b);
147 result = result | ((b & 0x7F) << shift);
148 if ((b & 0x80) == 0) break;
149 shift += 7;
150 }
151
152 *length = static_cast<int>(pc_ - pos);
153 if (pc_ == end && (b & 0x80)) {
154 error(pc_ - 1, "varint too large");
155 } else {
156 TRACE("= %u\n", result);
157 }
158 return result;
112 } 159 }
113 160 return traceOffEnd<uint32_t>();
114 const byte* pos = pc_;
115 const byte* end = pc_ + 5;
116 if (end > limit_) end = limit_;
117
118 uint32_t result = 0;
119 int shift = 0;
120 byte b = 0;
121 while (pc_ < end) {
122 b = *pc_++;
123 TRACE("%02x ", b);
124 result = result | ((b & 0x7F) << shift);
125 if ((b & 0x80) == 0) break;
126 shift += 7;
127 }
128
129 *length = static_cast<int>(pc_ - pos);
130 if (pc_ == end && (b & 0x80)) {
131 error(pc_ - 1, "varint too large");
132 } else {
133 TRACE("= %u\n", result);
134 }
135 return result;
136 } 161 }
137 162
138 // Check that at least {size} bytes exist between {pc_} and {limit_}. 163 // Check that at least {size} bytes exist between {pc_} and {limit_}.
139 bool checkAvailable(int size) { 164 bool checkAvailable(int size) {
140 if (pc_ < start_ || (pc_ + size) > limit_) { 165 if (pc_ < start_ || (pc_ + size) > limit_) {
141 error(pc_, nullptr, "expected %d bytes, fell off end", size); 166 error(pc_, nullptr, "expected %d bytes, fell off end", size);
142 return false; 167 return false;
143 } else { 168 } else {
144 return true; 169 return true;
145 } 170 }
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 } 226 }
202 result.val = val; 227 result.val = val;
203 return result; 228 return result;
204 } 229 }
205 230
206 // Resets the boundaries of this decoder. 231 // Resets the boundaries of this decoder.
207 void Reset(const byte* start, const byte* end) { 232 void Reset(const byte* start, const byte* end) {
208 start_ = start; 233 start_ = start;
209 pc_ = start; 234 pc_ = start;
210 limit_ = end; 235 limit_ = end;
236 end_ = end;
211 error_pc_ = nullptr; 237 error_pc_ = nullptr;
212 error_pt_ = nullptr; 238 error_pt_ = nullptr;
213 error_msg_.Reset(nullptr); 239 error_msg_.Reset(nullptr);
214 } 240 }
215 241
216 bool ok() const { return error_pc_ == nullptr; } 242 bool ok() const { return error_pc_ == nullptr; }
217 bool failed() const { return error_pc_ != nullptr; } 243 bool failed() const { return error_pc_ != nullptr; }
218 244
219 protected: 245 protected:
220 const byte* start_; 246 const byte* start_;
221 const byte* pc_; 247 const byte* pc_;
222 const byte* limit_; 248 const byte* limit_;
249 const byte* end_;
223 const byte* error_pc_; 250 const byte* error_pc_;
224 const byte* error_pt_; 251 const byte* error_pt_;
225 base::SmartArrayPointer<char> error_msg_; 252 base::SmartArrayPointer<char> error_msg_;
226 }; 253 };
227 254
228 #undef TRACE 255 #undef TRACE
229 } // namespace wasm 256 } // namespace wasm
230 } // namespace internal 257 } // namespace internal
231 } // namespace v8 258 } // namespace v8
232 259
233 #endif // V8_WASM_DECODER_H_ 260 #endif // V8_WASM_DECODER_H_
OLDNEW
« no previous file with comments | « src/wasm/ast-decoder.cc ('k') | src/wasm/module-decoder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698