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

Side by Side Diff: runtime/lib/typed_data.cc

Issue 24239003: Fix range checks for typed data in native code and the optimizer. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/flow_graph_optimizer.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 (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/bootstrap_natives.h" 5 #include "vm/bootstrap_natives.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 8
9 #include "vm/bigint_operations.h" 9 #include "vm/bigint_operations.h"
10 #include "vm/exceptions.h" 10 #include "vm/exceptions.h"
11 #include "vm/native_entry.h" 11 #include "vm/native_entry.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 13
14 namespace dart { 14 namespace dart {
15 15
16 // TypedData. 16 // TypedData.
17 17
18 // Checks to see if offset_in_bytes is in the range.
19 static bool RangeCheck(intptr_t offset_in_bytes, intptr_t length_in_bytes) {
20 return ((offset_in_bytes >= 0) &&
21 (length_in_bytes > 0) &&
22 (offset_in_bytes < length_in_bytes));
23 }
24
25
26 // Checks to see if offsetInBytes + num_bytes is in the range. 18 // Checks to see if offsetInBytes + num_bytes is in the range.
27 static void SetRangeCheck(intptr_t offset_in_bytes, 19 static void RangeCheck(intptr_t offset_in_bytes,
28 intptr_t num_bytes, 20 intptr_t access_size,
29 intptr_t length_in_bytes, 21 intptr_t length_in_bytes,
30 intptr_t element_size_in_bytes) { 22 intptr_t element_size_in_bytes) {
31 if (!Utils::RangeCheck(offset_in_bytes, num_bytes, length_in_bytes)) { 23 if (!Utils::RangeCheck(offset_in_bytes, access_size, length_in_bytes)) {
32 const String& error = String::Handle(String::NewFormatted( 24 const String& error = String::Handle(String::NewFormatted(
33 "index (%" Pd ") must be in the range [0..%" Pd ")", 25 "index (%" Pd ") must be in the range [0..%" Pd ")",
34 (offset_in_bytes / element_size_in_bytes), 26 (offset_in_bytes + access_size) / element_size_in_bytes,
35 (length_in_bytes / element_size_in_bytes))); 27 (length_in_bytes / element_size_in_bytes)));
36 const Array& args = Array::Handle(Array::New(1)); 28 const Array& args = Array::Handle(Array::New(1));
37 args.SetAt(0, error); 29 args.SetAt(0, error);
38 Exceptions::ThrowByType(Exceptions::kRange, args); 30 Exceptions::ThrowByType(Exceptions::kRange, args);
39 } 31 }
40 } 32 }
41 33
42 34
43 // Checks to see if a length will not result in an OOM error. 35 // Checks to see if a length will not result in an OOM error.
44 static void LengthCheck(intptr_t len, intptr_t max) { 36 static void LengthCheck(intptr_t len, intptr_t max) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 const Smi& length) { 75 const Smi& length) {
84 const DstType& dst_array = DstType::Cast(dst); 76 const DstType& dst_array = DstType::Cast(dst);
85 const SrcType& src_array = SrcType::Cast(src); 77 const SrcType& src_array = SrcType::Cast(src);
86 intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes(); 78 intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes();
87 intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes; 79 intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes;
88 intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes; 80 intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes;
89 intptr_t length_in_bytes = length.Value() * element_size_in_bytes; 81 intptr_t length_in_bytes = length.Value() * element_size_in_bytes;
90 if (dst_array.ElementType() != src_array.ElementType()) { 82 if (dst_array.ElementType() != src_array.ElementType()) {
91 return Bool::False().raw(); 83 return Bool::False().raw();
92 } 84 }
93 SetRangeCheck(src_offset_in_bytes, 85 RangeCheck(src_offset_in_bytes,
94 length_in_bytes, 86 length_in_bytes,
95 src_array.LengthInBytes(), 87 src_array.LengthInBytes(),
96 element_size_in_bytes); 88 element_size_in_bytes);
97 SetRangeCheck(dst_offset_in_bytes, 89 RangeCheck(dst_offset_in_bytes,
98 length_in_bytes, 90 length_in_bytes,
99 dst_array.LengthInBytes(), 91 dst_array.LengthInBytes(),
100 element_size_in_bytes); 92 element_size_in_bytes);
101 TypedData::Copy<DstType, SrcType>(dst_array, dst_offset_in_bytes, 93 TypedData::Copy<DstType, SrcType>(dst_array, dst_offset_in_bytes,
102 src_array, src_offset_in_bytes, 94 src_array, src_offset_in_bytes,
103 length_in_bytes); 95 length_in_bytes);
104 return Bool::True().raw(); 96 return Bool::True().raw();
105 } 97 }
106 98
107 99
108 DEFINE_NATIVE_ENTRY(TypedData_setRange, 5) { 100 DEFINE_NATIVE_ENTRY(TypedData_setRange, 5) {
109 GET_NON_NULL_NATIVE_ARGUMENT(Instance, dst, arguments->NativeArgAt(0)); 101 GET_NON_NULL_NATIVE_ARGUMENT(Instance, dst, arguments->NativeArgAt(0));
110 GET_NON_NULL_NATIVE_ARGUMENT(Smi, dst_start, arguments->NativeArgAt(1)); 102 GET_NON_NULL_NATIVE_ARGUMENT(Smi, dst_start, arguments->NativeArgAt(1));
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 } \ 168 } \
177 169
178 170
179 #define TYPED_DATA_NEW_NATIVE(name) \ 171 #define TYPED_DATA_NEW_NATIVE(name) \
180 TYPED_DATA_NEW(name) \ 172 TYPED_DATA_NEW(name) \
181 EXT_TYPED_DATA_NEW(name) \ 173 EXT_TYPED_DATA_NEW(name) \
182 174
183 175
184 CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE) 176 CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE)
185 177
186 #define TYPED_DATA_GETTER(getter, object) \ 178 #define TYPED_DATA_GETTER(getter, object, access_size) \
187 DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \ 179 DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \
188 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \ 180 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
189 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \ 181 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
190 if (instance.IsTypedData()) { \ 182 if (instance.IsTypedData()) { \
191 const TypedData& array = TypedData::Cast(instance); \ 183 const TypedData& array = TypedData::Cast(instance); \
192 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 184 RangeCheck(offsetInBytes.Value(), access_size, \
185 array.LengthInBytes(), access_size); \
193 return object::New(array.getter(offsetInBytes.Value())); \ 186 return object::New(array.getter(offsetInBytes.Value())); \
194 } \ 187 } \
195 if (instance.IsExternalTypedData()) { \ 188 if (instance.IsExternalTypedData()) { \
196 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \ 189 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
197 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 190 RangeCheck(offsetInBytes.Value(), access_size, \
191 array.LengthInBytes(), access_size); \
198 return object::New(array.getter(offsetInBytes.Value())); \ 192 return object::New(array.getter(offsetInBytes.Value())); \
199 } \ 193 } \
200 const String& error = String::Handle(String::NewFormatted( \ 194 const String& error = String::Handle(String::NewFormatted( \
201 "Expected a TypedData object but found %s", instance.ToCString())); \ 195 "Expected a TypedData object but found %s", instance.ToCString())); \
202 const Array& args = Array::Handle(Array::New(1)); \ 196 const Array& args = Array::Handle(Array::New(1)); \
203 args.SetAt(0, error); \ 197 args.SetAt(0, error); \
204 Exceptions::ThrowByType(Exceptions::kArgument, args); \ 198 Exceptions::ThrowByType(Exceptions::kArgument, args); \
205 return object::null(); \ 199 return object::null(); \
206 } \ 200 } \
207 201
208 202
209 #define TYPED_DATA_SETTER(setter, object, get_object_value) \ 203 #define TYPED_DATA_SETTER(setter, object, get_object_value, access_size) \
210 DEFINE_NATIVE_ENTRY(TypedData_##setter, 3) { \ 204 DEFINE_NATIVE_ENTRY(TypedData_##setter, 3) { \
211 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \ 205 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
212 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \ 206 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
213 GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \ 207 GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \
214 if (instance.IsTypedData()) { \ 208 if (instance.IsTypedData()) { \
215 const TypedData& array = TypedData::Cast(instance); \ 209 const TypedData& array = TypedData::Cast(instance); \
216 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 210 RangeCheck(offsetInBytes.Value(), access_size, \
211 array.LengthInBytes(), access_size); \
217 array.setter(offsetInBytes.Value(), value.get_object_value()); \ 212 array.setter(offsetInBytes.Value(), value.get_object_value()); \
218 } else if (instance.IsExternalTypedData()) { \ 213 } else if (instance.IsExternalTypedData()) { \
219 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \ 214 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
220 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 215 RangeCheck(offsetInBytes.Value(), access_size, \
216 array.LengthInBytes(), access_size); \
221 array.setter(offsetInBytes.Value(), value.get_object_value()); \ 217 array.setter(offsetInBytes.Value(), value.get_object_value()); \
222 } else { \ 218 } else { \
223 const String& error = String::Handle(String::NewFormatted( \ 219 const String& error = String::Handle(String::NewFormatted( \
224 "Expected a TypedData object but found %s", instance.ToCString())); \ 220 "Expected a TypedData object but found %s", instance.ToCString())); \
225 const Array& args = Array::Handle(Array::New(1)); \ 221 const Array& args = Array::Handle(Array::New(1)); \
226 args.SetAt(0, error); \ 222 args.SetAt(0, error); \
227 Exceptions::ThrowByType(Exceptions::kArgument, args); \ 223 Exceptions::ThrowByType(Exceptions::kArgument, args); \
228 } \ 224 } \
229 return Object::null(); \ 225 return Object::null(); \
230 } 226 }
231 227
232 228
233 #define TYPED_DATA_UINT64_GETTER(getter, object) \ 229 #define TYPED_DATA_UINT64_GETTER(getter, object) \
234 DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \ 230 DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \
235 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \ 231 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
236 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \ 232 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
237 uint64_t value = 0; \ 233 uint64_t value = 0; \
238 if (instance.IsTypedData()) { \ 234 if (instance.IsTypedData()) { \
239 const TypedData& array = TypedData::Cast(instance); \ 235 const TypedData& array = TypedData::Cast(instance); \
240 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 236 RangeCheck(offsetInBytes.Value(), 8, array.LengthInBytes(), 8); \
241 value = array.getter(offsetInBytes.Value()); \ 237 value = array.getter(offsetInBytes.Value()); \
242 } else if (instance.IsExternalTypedData()) { \ 238 } else if (instance.IsExternalTypedData()) { \
243 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \ 239 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
244 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 240 RangeCheck(offsetInBytes.Value(), 8, array.LengthInBytes(), 8); \
245 value = array.getter(offsetInBytes.Value()); \ 241 value = array.getter(offsetInBytes.Value()); \
246 } else { \ 242 } else { \
247 const String& error = String::Handle(String::NewFormatted( \ 243 const String& error = String::Handle(String::NewFormatted( \
248 "Expected a TypedData object but found %s", instance.ToCString())); \ 244 "Expected a TypedData object but found %s", instance.ToCString())); \
249 const Array& args = Array::Handle(Array::New(1)); \ 245 const Array& args = Array::Handle(Array::New(1)); \
250 args.SetAt(0, error); \ 246 args.SetAt(0, error); \
251 Exceptions::ThrowByType(Exceptions::kArgument, args); \ 247 Exceptions::ThrowByType(Exceptions::kArgument, args); \
252 } \ 248 } \
253 return Integer::NewFromUint64(value); \ 249 return Integer::NewFromUint64(value); \
254 } \ 250 } \
(...skipping 10 matching lines...) Expand all
265 if (value.IsBigint()) { \ 261 if (value.IsBigint()) { \
266 const Bigint& bigint = Bigint::Cast(value); \ 262 const Bigint& bigint = Bigint::Cast(value); \
267 ASSERT(BigintOperations::FitsIntoUint64(bigint)); \ 263 ASSERT(BigintOperations::FitsIntoUint64(bigint)); \
268 object_value = BigintOperations::AbsToUint64(bigint); \ 264 object_value = BigintOperations::AbsToUint64(bigint); \
269 } else { \ 265 } else { \
270 ASSERT(value.IsMint() || value.IsSmi()); \ 266 ASSERT(value.IsMint() || value.IsSmi()); \
271 object_value = value.AsInt64Value(); \ 267 object_value = value.AsInt64Value(); \
272 } \ 268 } \
273 if (instance.IsTypedData()) { \ 269 if (instance.IsTypedData()) { \
274 const TypedData& array = TypedData::Cast(instance); \ 270 const TypedData& array = TypedData::Cast(instance); \
275 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 271 RangeCheck(offsetInBytes.Value(), 8, array.LengthInBytes(), 8); \
276 array.setter(offsetInBytes.Value(), object_value); \ 272 array.setter(offsetInBytes.Value(), object_value); \
277 } else if (instance.IsExternalTypedData()) { \ 273 } else if (instance.IsExternalTypedData()) { \
278 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \ 274 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
279 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \ 275 RangeCheck(offsetInBytes.Value(), 8, array.LengthInBytes(), 8); \
280 array.setter(offsetInBytes.Value(), object_value); \ 276 array.setter(offsetInBytes.Value(), object_value); \
281 } else { \ 277 } else { \
282 const String& error = String::Handle(String::NewFormatted( \ 278 const String& error = String::Handle(String::NewFormatted( \
283 "Expected a TypedData object but found %s", instance.ToCString())); \ 279 "Expected a TypedData object but found %s", instance.ToCString())); \
284 const Array& args = Array::Handle(Array::New(1)); \ 280 const Array& args = Array::Handle(Array::New(1)); \
285 args.SetAt(0, error); \ 281 args.SetAt(0, error); \
286 Exceptions::ThrowByType(Exceptions::kArgument, args); \ 282 Exceptions::ThrowByType(Exceptions::kArgument, args); \
287 } \ 283 } \
288 return Object::null(); \ 284 return Object::null(); \
289 } 285 }
290 286
291 287
292 #define TYPED_DATA_NATIVES(getter, setter, object, get_object_value) \ 288 #define TYPED_DATA_NATIVES(getter, \
293 TYPED_DATA_GETTER(getter, object) \ 289 setter, \
294 TYPED_DATA_SETTER(setter, object, get_object_value) \ 290 object, \
291 get_object_value, \
292 access_size) \
293 TYPED_DATA_GETTER(getter, object, access_size) \
294 TYPED_DATA_SETTER(setter, object, get_object_value, access_size) \
295 295
296 296
297 #define TYPED_DATA_UINT64_NATIVES(getter, setter, object) \ 297 #define TYPED_DATA_UINT64_NATIVES(getter, setter, object) \
298 TYPED_DATA_UINT64_GETTER(getter, object) \ 298 TYPED_DATA_UINT64_GETTER(getter, object) \
299 TYPED_DATA_UINT64_SETTER(setter, object) \ 299 TYPED_DATA_UINT64_SETTER(setter, object) \
300 300
301 301
302 TYPED_DATA_NATIVES(GetInt8, SetInt8, Smi, Value) 302 TYPED_DATA_NATIVES(GetInt8, SetInt8, Smi, Value, 1)
303 TYPED_DATA_NATIVES(GetUint8, SetUint8, Smi, Value) 303 TYPED_DATA_NATIVES(GetUint8, SetUint8, Smi, Value, 1)
304 TYPED_DATA_NATIVES(GetInt16, SetInt16, Smi, Value) 304 TYPED_DATA_NATIVES(GetInt16, SetInt16, Smi, Value, 2)
305 TYPED_DATA_NATIVES(GetUint16, SetUint16, Smi, Value) 305 TYPED_DATA_NATIVES(GetUint16, SetUint16, Smi, Value, 2)
306 TYPED_DATA_NATIVES(GetInt32, SetInt32, Integer, AsInt64Value) 306 TYPED_DATA_NATIVES(GetInt32, SetInt32, Integer, AsInt64Value, 4)
307 TYPED_DATA_NATIVES(GetUint32, SetUint32, Integer, AsInt64Value) 307 TYPED_DATA_NATIVES(GetUint32, SetUint32, Integer, AsInt64Value, 4)
308 TYPED_DATA_NATIVES(GetInt64, SetInt64, Integer, AsInt64Value) 308 TYPED_DATA_NATIVES(GetInt64, SetInt64, Integer, AsInt64Value, 8)
309 TYPED_DATA_UINT64_NATIVES(GetUint64, SetUint64, Integer) 309 TYPED_DATA_UINT64_NATIVES(GetUint64, SetUint64, Integer)
310 TYPED_DATA_NATIVES(GetFloat32, SetFloat32, Double, value) 310 TYPED_DATA_NATIVES(GetFloat32, SetFloat32, Double, value, 4)
311 TYPED_DATA_NATIVES(GetFloat64, SetFloat64, Double, value) 311 TYPED_DATA_NATIVES(GetFloat64, SetFloat64, Double, value, 8)
312 TYPED_DATA_NATIVES(GetFloat32x4, SetFloat32x4, Float32x4, value) 312 TYPED_DATA_NATIVES(GetFloat32x4, SetFloat32x4, Float32x4, value, 16)
313 313
314 314
315 DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt16, 2) { 315 DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt16, 2) {
316 GET_NON_NULL_NATIVE_ARGUMENT(Smi, host_value, arguments->NativeArgAt(0)); 316 GET_NON_NULL_NATIVE_ARGUMENT(Smi, host_value, arguments->NativeArgAt(0));
317 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1)); 317 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
318 int16_t value = host_value.Value(); 318 int16_t value = host_value.Value();
319 if (little_endian.value()) { 319 if (little_endian.value()) {
320 value = Utils::HostToLittleEndian16(value); 320 value = Utils::HostToLittleEndian16(value);
321 } else { 321 } else {
322 value = Utils::HostToBigEndian16(value); 322 value = Utils::HostToBigEndian16(value);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 value = bit_cast<double>( 421 value = bit_cast<double>(
422 Utils::HostToLittleEndian64(bit_cast<uint64_t>(value))); 422 Utils::HostToLittleEndian64(bit_cast<uint64_t>(value)));
423 } else { 423 } else {
424 value = bit_cast<double>( 424 value = bit_cast<double>(
425 Utils::HostToBigEndian64(bit_cast<uint64_t>(value))); 425 Utils::HostToBigEndian64(bit_cast<uint64_t>(value)));
426 } 426 }
427 return Double::New(value); 427 return Double::New(value);
428 } 428 }
429 429
430 } // namespace dart 430 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/flow_graph_optimizer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698