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

Side by Side Diff: runtime/vm/dart_api_impl.cc

Issue 957483002: Verify acquired typed data: allow detection of use-after-free. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 9 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/dart_api_impl_test.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 "include/dart_api.h" 5 #include "include/dart_api.h"
6 #include "include/dart_mirrors_api.h" 6 #include "include/dart_mirrors_api.h"
7 #include "include/dart_native_api.h" 7 #include "include/dart_native_api.h"
8 8
9 #include "platform/assert.h" 9 #include "platform/assert.h"
10 #include "vm/class_finalizer.h" 10 #include "vm/class_finalizer.h"
(...skipping 3380 matching lines...) Expand 10 before | Expand all | Expand 10 after
3391 const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(typed_data)); 3391 const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(typed_data));
3392 args.SetAt(1, obj); 3392 args.SetAt(1, obj);
3393 3393
3394 // Invoke the factory constructor and return the new object. 3394 // Invoke the factory constructor and return the new object.
3395 result = DartEntry::InvokeFunction(factory, args); 3395 result = DartEntry::InvokeFunction(factory, args);
3396 ASSERT(result.IsInstance() || result.IsNull() || result.IsError()); 3396 ASSERT(result.IsInstance() || result.IsNull() || result.IsError());
3397 return Api::NewHandle(isolate, result.raw()); 3397 return Api::NewHandle(isolate, result.raw());
3398 } 3398 }
3399 3399
3400 3400
3401 // Structure to record acquired typed data for verification purposes.
3402 class AcquiredData {
3403 public:
3404 AcquiredData(void* data, intptr_t size_in_bytes, bool copy)
3405 : size_in_bytes_(size_in_bytes), data_(data), data_copy_(NULL) {
3406 if (copy) {
3407 data_copy_ = malloc(size_in_bytes_);
3408 memmove(data_copy_, data_, size_in_bytes_);
3409 }
3410 }
3411
3412 // The pointer to hand out via the API.
3413 void* GetData() const { return data_copy_ != NULL ? data_copy_ : data_; }
3414
3415 // Writes back and deletes/zaps, if a copy was made.
3416 ~AcquiredData() {
3417 if (data_copy_ != NULL) {
3418 memmove(data_, data_copy_, size_in_bytes_);
3419 memset(data_copy_, kZapReleasedByte, size_in_bytes_);
3420 free(data_copy_);
3421 }
3422 }
3423
3424 private:
3425 static const uint8_t kZapReleasedByte = 0xda;
3426 intptr_t size_in_bytes_;
3427 void* data_;
3428 void* data_copy_;
3429
3430 DISALLOW_COPY_AND_ASSIGN(AcquiredData);
3431 };
3432
3433
3401 DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, 3434 DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object,
3402 Dart_TypedData_Type* type, 3435 Dart_TypedData_Type* type,
3403 void** data, 3436 void** data,
3404 intptr_t* len) { 3437 intptr_t* len) {
3405 Isolate* isolate = Isolate::Current(); 3438 Isolate* isolate = Isolate::Current();
3406 DARTSCOPE(isolate); 3439 DARTSCOPE(isolate);
3407 intptr_t class_id = Api::ClassId(object); 3440 intptr_t class_id = Api::ClassId(object);
3408 if (!RawObject::IsExternalTypedDataClassId(class_id) && 3441 if (!RawObject::IsExternalTypedDataClassId(class_id) &&
3409 !RawObject::IsTypedDataViewClassId(class_id) && 3442 !RawObject::IsTypedDataViewClassId(class_id) &&
3410 !RawObject::IsTypedDataClassId(class_id)) { 3443 !RawObject::IsTypedDataClassId(class_id)) {
3411 RETURN_TYPE_ERROR(isolate, object, 'TypedData'); 3444 RETURN_TYPE_ERROR(isolate, object, 'TypedData');
3412 } 3445 }
3413 if (type == NULL) { 3446 if (type == NULL) {
3414 RETURN_NULL_ERROR(type); 3447 RETURN_NULL_ERROR(type);
3415 } 3448 }
3416 if (data == NULL) { 3449 if (data == NULL) {
3417 RETURN_NULL_ERROR(data); 3450 RETURN_NULL_ERROR(data);
3418 } 3451 }
3419 if (len == NULL) { 3452 if (len == NULL) {
3420 RETURN_NULL_ERROR(len); 3453 RETURN_NULL_ERROR(len);
3421 } 3454 }
3422 // Get the type of typed data object. 3455 // Get the type of typed data object.
3423 *type = GetType(class_id); 3456 *type = GetType(class_id);
3457 intptr_t length = 0;
3458 intptr_t size_in_bytes = 0;
3459 void* data_tmp = NULL;
3460 bool external = false;
3424 // If it is an external typed data object just return the data field. 3461 // If it is an external typed data object just return the data field.
3425 if (RawObject::IsExternalTypedDataClassId(class_id)) { 3462 if (RawObject::IsExternalTypedDataClassId(class_id)) {
3426 const ExternalTypedData& obj = 3463 const ExternalTypedData& obj =
3427 Api::UnwrapExternalTypedDataHandle(isolate, object); 3464 Api::UnwrapExternalTypedDataHandle(isolate, object);
3428 ASSERT(!obj.IsNull()); 3465 ASSERT(!obj.IsNull());
3429 *len = obj.Length(); 3466 length = obj.Length();
3430 *data = obj.DataAddr(0); 3467 size_in_bytes = length * ExternalTypedData::ElementSizeInBytes(class_id);
3468 data_tmp = obj.DataAddr(0);
3469 external = true;
3431 } else if (RawObject::IsTypedDataClassId(class_id)) { 3470 } else if (RawObject::IsTypedDataClassId(class_id)) {
3432 // Regular typed data object, set up some GC and API callback guards. 3471 // Regular typed data object, set up some GC and API callback guards.
3433 const TypedData& obj = Api::UnwrapTypedDataHandle(isolate, object); 3472 const TypedData& obj = Api::UnwrapTypedDataHandle(isolate, object);
3434 ASSERT(!obj.IsNull()); 3473 ASSERT(!obj.IsNull());
3435 *len = obj.Length(); 3474 length = obj.Length();
3475 size_in_bytes = length * TypedData::ElementSizeInBytes(class_id);
3436 isolate->IncrementNoGCScopeDepth(); 3476 isolate->IncrementNoGCScopeDepth();
3437 START_NO_CALLBACK_SCOPE(isolate); 3477 START_NO_CALLBACK_SCOPE(isolate);
3438 *data = obj.DataAddr(0); 3478 data_tmp = obj.DataAddr(0);
3439 } else { 3479 } else {
3440 ASSERT(RawObject::IsTypedDataViewClassId(class_id)); 3480 ASSERT(RawObject::IsTypedDataViewClassId(class_id));
3441 const Instance& view_obj = Api::UnwrapInstanceHandle(isolate, object); 3481 const Instance& view_obj = Api::UnwrapInstanceHandle(isolate, object);
3442 ASSERT(!view_obj.IsNull()); 3482 ASSERT(!view_obj.IsNull());
3443 Smi& val = Smi::Handle(); 3483 Smi& val = Smi::Handle();
3444 val ^= TypedDataView::Length(view_obj); 3484 val ^= TypedDataView::Length(view_obj);
3445 *len = val.Value(); 3485 length = val.Value();
3486 size_in_bytes = length * TypedDataView::ElementSizeInBytes(class_id);
3446 val ^= TypedDataView::OffsetInBytes(view_obj); 3487 val ^= TypedDataView::OffsetInBytes(view_obj);
3447 intptr_t offset_in_bytes = val.Value(); 3488 intptr_t offset_in_bytes = val.Value();
3448 const Instance& obj = Instance::Handle(TypedDataView::Data(view_obj)); 3489 const Instance& obj = Instance::Handle(TypedDataView::Data(view_obj));
3449 isolate->IncrementNoGCScopeDepth(); 3490 isolate->IncrementNoGCScopeDepth();
3450 START_NO_CALLBACK_SCOPE(isolate); 3491 START_NO_CALLBACK_SCOPE(isolate);
3451 if (TypedData::IsTypedData(obj)) { 3492 if (TypedData::IsTypedData(obj)) {
3452 const TypedData& data_obj = TypedData::Cast(obj); 3493 const TypedData& data_obj = TypedData::Cast(obj);
3453 *data = data_obj.DataAddr(offset_in_bytes); 3494 data_tmp = data_obj.DataAddr(offset_in_bytes);
3454 } else { 3495 } else {
3455 ASSERT(ExternalTypedData::IsExternalTypedData(obj)); 3496 ASSERT(ExternalTypedData::IsExternalTypedData(obj));
3456 const ExternalTypedData& data_obj = ExternalTypedData::Cast(obj); 3497 const ExternalTypedData& data_obj = ExternalTypedData::Cast(obj);
3457 *data = data_obj.DataAddr(offset_in_bytes); 3498 data_tmp = data_obj.DataAddr(offset_in_bytes);
3499 external = true;
3458 } 3500 }
3459 } 3501 }
3460 if (FLAG_verify_acquired_data) { 3502 if (FLAG_verify_acquired_data) {
3461 // For now, we just verify that acquire/release are properly matched
3462 // per object.
3463 // TODO(koda): Copy internal data to/from a side buffer which is unmapped
3464 // on release to catch use-after-release bugs.
3465 const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object)); 3503 const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
3466 WeakTable* table = isolate->api_state()->acquired_table(); 3504 WeakTable* table = isolate->api_state()->acquired_table();
3467 intptr_t current = table->GetValue(obj.raw()); 3505 intptr_t current = table->GetValue(obj.raw());
3468 if (current != 0) { 3506 if (current != 0) {
3469 ASSERT(current == 1);
3470 return Api::NewError("Data was already acquired for this object."); 3507 return Api::NewError("Data was already acquired for this object.");
3471 } 3508 }
3472 table->SetValue(obj.raw(), 1); 3509 // Do not make a copy if the data is external. Some callers expect external
3510 // data to remain in place, even though the API spec doesn't guarantee it.
3511 // TODO(koda/asiva): Make final decision and document it.
3512 AcquiredData* ad = new AcquiredData(data_tmp, size_in_bytes, !external);
3513 table->SetValue(obj.raw(), reinterpret_cast<intptr_t>(ad));
3514 data_tmp = ad->GetData();
3473 } 3515 }
3516 *data = data_tmp;
3517 *len = length;
3474 return Api::Success(); 3518 return Api::Success();
3475 } 3519 }
3476 3520
3477 3521
3478 DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) { 3522 DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) {
3479 Isolate* isolate = Isolate::Current(); 3523 Isolate* isolate = Isolate::Current();
3480 DARTSCOPE(isolate); 3524 DARTSCOPE(isolate);
3481 intptr_t class_id = Api::ClassId(object); 3525 intptr_t class_id = Api::ClassId(object);
3482 if (!RawObject::IsExternalTypedDataClassId(class_id) && 3526 if (!RawObject::IsExternalTypedDataClassId(class_id) &&
3483 !RawObject::IsTypedDataViewClassId(class_id) && 3527 !RawObject::IsTypedDataViewClassId(class_id) &&
3484 !RawObject::IsTypedDataClassId(class_id)) { 3528 !RawObject::IsTypedDataClassId(class_id)) {
3485 RETURN_TYPE_ERROR(isolate, object, 'TypedData'); 3529 RETURN_TYPE_ERROR(isolate, object, 'TypedData');
3486 } 3530 }
3487 if (!RawObject::IsExternalTypedDataClassId(class_id)) { 3531 if (!RawObject::IsExternalTypedDataClassId(class_id)) {
3488 isolate->DecrementNoGCScopeDepth(); 3532 isolate->DecrementNoGCScopeDepth();
3489 END_NO_CALLBACK_SCOPE(isolate); 3533 END_NO_CALLBACK_SCOPE(isolate);
3490 } 3534 }
3491 if (FLAG_verify_acquired_data) { 3535 if (FLAG_verify_acquired_data) {
3492 const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object)); 3536 const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
3493 WeakTable* table = isolate->api_state()->acquired_table(); 3537 WeakTable* table = isolate->api_state()->acquired_table();
3494 intptr_t current = table->GetValue(obj.raw()); 3538 intptr_t current = table->GetValue(obj.raw());
3495 if (current != 1) { 3539 if (current == 0) {
3496 ASSERT(current == 0);
3497 return Api::NewError("Data was not acquired for this object."); 3540 return Api::NewError("Data was not acquired for this object.");
3498 } 3541 }
3499 // Delete entry from table. 3542 AcquiredData* ad = reinterpret_cast<AcquiredData*>(current);
3500 table->SetValue(obj.raw(), 0); 3543 table->SetValue(obj.raw(), 0); // Delete entry from table.
3544 delete ad;
3501 } 3545 }
3502 return Api::Success(); 3546 return Api::Success();
3503 } 3547 }
3504 3548
3505 3549
3506 DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle object) { 3550 DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle object) {
3507 Isolate* isolate = Isolate::Current(); 3551 Isolate* isolate = Isolate::Current();
3508 CHECK_ISOLATE(isolate); 3552 CHECK_ISOLATE(isolate);
3509 intptr_t class_id = Api::ClassId(object); 3553 intptr_t class_id = Api::ClassId(object);
3510 if (class_id != kByteBufferCid) { 3554 if (class_id != kByteBufferCid) {
(...skipping 1965 matching lines...) Expand 10 before | Expand all | Expand 10 after
5476 5520
5477 5521
5478 DART_EXPORT void Dart_RegisterRootServiceRequestCallback( 5522 DART_EXPORT void Dart_RegisterRootServiceRequestCallback(
5479 const char* name, 5523 const char* name,
5480 Dart_ServiceRequestCallback callback, 5524 Dart_ServiceRequestCallback callback,
5481 void* user_data) { 5525 void* user_data) {
5482 Service::RegisterRootEmbedderCallback(name, callback, user_data); 5526 Service::RegisterRootEmbedderCallback(name, callback, user_data);
5483 } 5527 }
5484 5528
5485 } // namespace dart 5529 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/dart_api_impl_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698