| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // These tests check that Torque-generated verifier functions crash the process |
| // when encountering data that doesn't fit the Torque type definitions. |
| |
| #include "src/api/api-inl.h" |
| #include "src/objects/descriptor-array.h" |
| #include "src/objects/map-inl.h" |
| #include "test/cctest/cctest.h" |
| #include "torque-generated/class-verifiers.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // Defines a pair of tests with similar code. The goal is to test that a |
| // specific action causes a failure, but that everything else in the test case |
| // succeeds. The general pattern should be: |
| // |
| // TEST_PAIR(Something) { |
| // do_setup_steps_that_always_succeed(); |
| // if (should_fail) { |
| // do_the_step_that_fails(); |
| // } |
| // do_teardown_steps_that_always_succeed(); |
| // } |
| // |
| // A corresponding entry in cctest.status specifies that all Fail* tests in this |
| // file must fail. |
| #define TEST_PAIR(Name) \ |
| static void Name(bool should_fail); \ |
| TEST(Pass##Name) { Name(false); } \ |
| TEST(Fail##Name) { Name(true); } \ |
| static void Name(bool should_fail) |
| |
| #ifdef VERIFY_HEAP |
| |
| TEST_PAIR(TestWrongTypeInNormalField) { |
| CcTest::InitializeVM(); |
| v8::Isolate* isolate = CcTest::isolate(); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| v8::HandleScope scope(isolate); |
| v8::Local<v8::Value> v = CompileRun("({a: 3, b: 4})"); |
| Handle<JSObject> o = Handle<JSObject>::cast(v8::Utils::OpenHandle(*v)); |
| Handle<Object> original_elements( |
| TaggedField<Object>::load(*o, JSObject::kElementsOffset), i_isolate); |
| CHECK(original_elements->IsFixedArrayBase()); |
| |
| // There must be no GC (and therefore no verifiers running) until we can |
| // restore the modified data. |
| DisallowHeapAllocation no_gc; |
| |
| // Elements must be FixedArrayBase according to the Torque definition, so a |
| // JSObject should cause a failure. |
| TaggedField<Object>::store(*o, JSObject::kElementsOffset, *o); |
| if (should_fail) { |
| TorqueGeneratedClassVerifiers::JSObjectVerify(*o, i_isolate); |
| } |
| |
| // Put back the original value in case verifiers run on test shutdown. |
| TaggedField<Object>::store(*o, JSObject::kElementsOffset, *original_elements); |
| } |
| |
| TEST_PAIR(TestWrongStrongTypeInIndexedStructField) { |
| CcTest::InitializeVM(); |
| v8::Isolate* isolate = CcTest::isolate(); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| v8::HandleScope scope(isolate); |
| v8::Local<v8::Value> v = CompileRun("({a: 3, b: 4})"); |
| Handle<Object> o = v8::Utils::OpenHandle(*v); |
| Handle<Map> map(Handle<HeapObject>::cast(o)->map(), i_isolate); |
| Handle<DescriptorArray> descriptors(map->instance_descriptors(kRelaxedLoad), |
| i_isolate); |
| int offset = DescriptorArray::OffsetOfDescriptorAt(1) + |
| DescriptorArray::kEntryKeyOffset; |
| Handle<Object> original_key(TaggedField<Object>::load(*descriptors, offset), |
| i_isolate); |
| CHECK(original_key->IsString()); |
| |
| // There must be no GC (and therefore no verifiers running) until we can |
| // restore the modified data. |
| DisallowHeapAllocation no_gc; |
| |
| // Key must be Name|Undefined according to the Torque definition, so a |
| // JSObject should cause a failure. |
| TaggedField<Object>::store(*descriptors, offset, *o); |
| if (should_fail) { |
| TorqueGeneratedClassVerifiers::DescriptorArrayVerify(*descriptors, |
| i_isolate); |
| } |
| |
| // Put back the original value in case verifiers run on test shutdown. |
| TaggedField<Object>::store(*descriptors, offset, *original_key); |
| } |
| |
| TEST_PAIR(TestWrongWeakTypeInIndexedStructField) { |
| CcTest::InitializeVM(); |
| v8::Isolate* isolate = CcTest::isolate(); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| v8::HandleScope scope(isolate); |
| v8::Local<v8::Value> v = CompileRun("({a: 3, b: 4})"); |
| Handle<Object> o = v8::Utils::OpenHandle(*v); |
| Handle<Map> map(Handle<HeapObject>::cast(o)->map(), i_isolate); |
| Handle<DescriptorArray> descriptors(map->instance_descriptors(kRelaxedLoad), |
| i_isolate); |
| int offset = DescriptorArray::OffsetOfDescriptorAt(0) + |
| DescriptorArray::kEntryValueOffset; |
| Handle<Object> original_value(TaggedField<Object>::load(*descriptors, offset), |
| i_isolate); |
| |
| // There must be no GC (and therefore no verifiers running) until we can |
| // restore the modified data. |
| DisallowHeapAllocation no_gc; |
| |
| // Value can be JSAny, which includes JSObject, and it can be Weak<Map>, but |
| // it can't be Weak<JSObject>. |
| TaggedField<Object>::store(*descriptors, offset, *o); |
| TorqueGeneratedClassVerifiers::DescriptorArrayVerify(*descriptors, i_isolate); |
| MaybeObject weak = MaybeObject::MakeWeak(MaybeObject::FromObject(*o)); |
| TaggedField<MaybeObject>::store(*descriptors, offset, weak); |
| if (should_fail) { |
| TorqueGeneratedClassVerifiers::DescriptorArrayVerify(*descriptors, |
| i_isolate); |
| } |
| |
| // Put back the original value in case verifiers run on test shutdown. |
| TaggedField<Object>::store(*descriptors, offset, *original_value); |
| } |
| |
| TEST_PAIR(TestWrongOddball) { |
| CcTest::InitializeVM(); |
| v8::Isolate* isolate = CcTest::isolate(); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| v8::HandleScope scope(isolate); |
| v8::Local<v8::Value> v = CompileRun("new Date()"); |
| Handle<JSDate> date = Handle<JSDate>::cast(v8::Utils::OpenHandle(*v)); |
| Handle<Object> original_hour( |
| TaggedField<Object>::load(*date, JSDate::kHourOffset), i_isolate); |
| |
| // There must be no GC (and therefore no verifiers running) until we can |
| // restore the modified data. |
| DisallowHeapAllocation no_gc; |
| |
| // Hour is Undefined|Smi|NaN. Other oddballs like null should cause a failure. |
| TaggedField<Object>::store(*date, JSDate::kHourOffset, |
| *i_isolate->factory()->null_value()); |
| if (should_fail) { |
| TorqueGeneratedClassVerifiers::JSDateVerify(*date, i_isolate); |
| } |
| |
| // Put back the original value in case verifiers run on test shutdown. |
| TaggedField<Object>::store(*date, JSDate::kHourOffset, *original_hour); |
| } |
| |
| TEST_PAIR(TestWrongNumber) { |
| CcTest::InitializeVM(); |
| v8::Isolate* isolate = CcTest::isolate(); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| v8::HandleScope scope(isolate); |
| v8::Local<v8::Value> v = CompileRun("new Date()"); |
| Handle<JSDate> date = Handle<JSDate>::cast(v8::Utils::OpenHandle(*v)); |
| Handle<Object> original_hour( |
| TaggedField<Object>::load(*date, JSDate::kHourOffset), i_isolate); |
| v8::Local<v8::Value> v2 = CompileRun("1.1"); |
| Handle<Object> float_val = v8::Utils::OpenHandle(*v2); |
| |
| // There must be no GC (and therefore no verifiers running) until we can |
| // restore the modified data. |
| DisallowHeapAllocation no_gc; |
| |
| // Hour is Undefined|Smi|NaN. Other doubles like 1.1 should cause a failure. |
| TaggedField<Object>::store(*date, JSDate::kHourOffset, *float_val); |
| if (should_fail) { |
| TorqueGeneratedClassVerifiers::JSDateVerify(*date, i_isolate); |
| } |
| |
| // Put back the original value in case verifiers run on test shutdown. |
| TaggedField<Object>::store(*date, JSDate::kHourOffset, *original_hour); |
| } |
| |
| #endif // VERIFY_HEAP |
| |
| #undef TEST_PAIR |
| |
| } // namespace internal |
| } // namespace v8 |