Changeset 294017 in webkit
- Timestamp:
- May 10, 2022 2:55:45 PM (2 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/APICast.h
r292929 r294017 1 1 /* 2 * Copyright (C) 2006-20 19Apple Inc. All rights reserved.2 * Copyright (C) 2006-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 #define APICast_h 28 28 29 #include "Integrity.h" 29 30 #include "JSAPIValueWrapper.h" 30 31 #include "JSCJSValue.h" … … 53 54 { 54 55 ASSERT(context); 55 return reinterpret_cast<JSC::JSGlobalObject*>(const_cast<OpaqueJSContext*>(context));56 return JSC::Integrity::audit(reinterpret_cast<JSC::JSGlobalObject*>(const_cast<OpaqueJSContext*>(context))); 56 57 } 57 58 … … 59 60 { 60 61 ASSERT(context); 61 return reinterpret_cast<JSC::JSGlobalObject*>(context);62 return JSC::Integrity::audit(reinterpret_cast<JSC::JSGlobalObject*>(context)); 62 63 } 63 64 … … 84 85 if (!result) 85 86 return JSC::jsNull(); 86 if (result.isCell()) 87 if (result.isCell()) { 88 JSC::Integrity::audit(result.asCell()); 87 89 RELEASE_ASSERT(result.asCell()->methodTable()); 90 } 88 91 return result; 89 92 } … … 92 95 inline JSC::JSValue toJS(JSValueRef value) 93 96 { 94 return bitwise_cast<JSC::JSValue>(value);97 return JSC::Integrity::audit(bitwise_cast<JSC::JSValue>(value)); 95 98 } 96 99 #endif … … 107 110 JSC::JSValue result = bitwise_cast<JSC::JSValue>(v); 108 111 #endif 109 if (result && result.isCell()) 112 if (result && result.isCell()) { 113 JSC::Integrity::audit(result.asCell()); 110 114 RELEASE_ASSERT(result.asCell()->methodTable()); 115 } 111 116 return result; 112 117 } … … 115 120 inline JSC::JSObject* uncheckedToJS(JSObjectRef o) 116 121 { 117 return reinterpret_cast<JSC::JSObject*>(o);122 return JSC::Integrity::audit(reinterpret_cast<JSC::JSObject*>(o)); 118 123 } 119 124 … … 133 138 inline JSC::VM* toJS(JSContextGroupRef g) 134 139 { 135 return reinterpret_cast<JSC::VM*>(const_cast<OpaqueJSContextGroup*>(g));140 return JSC::Integrity::audit(reinterpret_cast<JSC::VM*>(const_cast<OpaqueJSContextGroup*>(g))); 136 141 } 137 142 … … 147 152 #else 148 153 UNUSED_PARAM(vm); 149 return bitwise_cast<JSValueRef>( v);154 return bitwise_cast<JSValueRef>(JSC::Integrity::audit(v)); 150 155 #endif 151 156 } … … 159 164 inline JSValueRef toRef(JSC::JSValue v) 160 165 { 161 return bitwise_cast<JSValueRef>( v);166 return bitwise_cast<JSValueRef>(JSC::Integrity::audit(v)); 162 167 } 163 168 #endif … … 165 170 inline JSObjectRef toRef(JSC::JSObject* o) 166 171 { 167 return reinterpret_cast<JSObjectRef>( o);172 return reinterpret_cast<JSObjectRef>(JSC::Integrity::audit(o)); 168 173 } 169 174 170 175 inline JSObjectRef toRef(const JSC::JSObject* o) 171 176 { 172 return reinterpret_cast<JSObjectRef>( const_cast<JSC::JSObject*>(o));177 return reinterpret_cast<JSObjectRef>(JSC::Integrity::audit(const_cast<JSC::JSObject*>(o))); 173 178 } 174 179 175 180 inline JSContextRef toRef(JSC::JSGlobalObject* globalObject) 176 181 { 177 return reinterpret_cast<JSContextRef>( globalObject);182 return reinterpret_cast<JSContextRef>(JSC::Integrity::audit(globalObject)); 178 183 } 179 184 180 185 inline JSGlobalContextRef toGlobalRef(JSC::JSGlobalObject* globalObject) 181 186 { 182 return reinterpret_cast<JSGlobalContextRef>( globalObject);187 return reinterpret_cast<JSGlobalContextRef>(JSC::Integrity::audit(globalObject)); 183 188 } 184 189 … … 190 195 inline JSContextGroupRef toRef(JSC::VM* g) 191 196 { 192 return reinterpret_cast<JSContextGroupRef>( g);197 return reinterpret_cast<JSContextGroupRef>(JSC::Integrity::audit(g)); 193 198 } 194 199 -
trunk/Source/JavaScriptCore/API/JSContext.mm
r293879 r294017 1 1 /* 2 * Copyright (C) 2013-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2013-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 28 28 #import "APICast.h" 29 29 #import "Completion.h" 30 #import "IntegrityInlines.h" 30 31 #import "JSBaseInternal.h" 31 32 #import "JSCInlines.h" -
trunk/Source/JavaScriptCore/API/JSContextRef.cpp
r293779 r294017 31 31 #include "CallFrame.h" 32 32 #include "InitializeThreading.h" 33 #include "IntegrityInlines.h" 33 34 #include "JSAPIGlobalObject.h" 34 35 #include "JSAPIWrapperObject.h" -
trunk/Source/JavaScriptCore/API/JSScript.mm
r291779 r294017 1 1 /* 2 * Copyright (C) 2019-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 32 32 #import "CodeCache.h" 33 33 #import "Identifier.h" 34 #import "IntegrityInlines.h" 34 35 #import "JSContextInternal.h" 35 36 #import "JSScriptSourceProvider.h" -
trunk/Source/JavaScriptCore/API/JSValue.mm
r293703 r294017 1 1 /* 2 * Copyright (C) 2013-20 18Apple Inc. All rights reserved.2 * Copyright (C) 2013-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 59 59 #if JSC_OBJC_API_ENABLED 60 60 61 using JSC::Integrity::audit; 62 61 63 NSString * const JSPropertyDescriptorWritableKey = @"writable"; 62 64 NSString * const JSPropertyDescriptorEnumerableKey = @"enumerable"; … … 971 973 auto it = m_objectMap.find(object); 972 974 if (it != m_objectMap.end()) 973 return it->value;975 return audit(it->value); 974 976 975 977 ObjcContainerConvertor::Task task = objectToValueWithoutCopy(m_context, object); 976 978 add(task); 977 return task.js;979 return audit(task.js); 978 980 } 979 981 … … 1005 1007 static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *context, id object) 1006 1008 { 1007 JSGlobalContextRef contextRef = [context JSGlobalContextRef];1009 JSGlobalContextRef contextRef = audit([context JSGlobalContextRef]); 1008 1010 1009 1011 if (!object) … … 1057 1059 ObjcContainerConvertor::Task task = objectToValueWithoutCopy(context, object); 1058 1060 if (task.type == ContainerNone) 1059 return task.js;1061 return audit(task.js); 1060 1062 1061 1063 JSC::JSLockHolder locker(toJS(contextRef)); … … 1088 1090 } while (!convertor.isWorkListEmpty()); 1089 1091 1090 return task.js;1092 return audit(task.js); 1091 1093 } 1092 1094 -
trunk/Source/JavaScriptCore/API/JSVirtualMachine.mm
r279179 r294017 1 1 /* 2 * Copyright (C) 2013-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2013-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 31 31 32 32 #import "APICast.h" 33 #import "IntegrityInlines.h" 33 34 #import "JITWorklist.h" 34 35 #import "JSManagedValueInternal.h" -
trunk/Source/JavaScriptCore/API/JSWeakPrivate.cpp
r261755 r294017 1 1 /* 2 * Copyright (C) 2017 Apple Inc. All rights reserved.2 * Copyright (C) 2017-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 28 28 29 29 #include "APICast.h" 30 #include "IntegrityInlines.h" 30 31 #include "Weak.h" 31 32 #include <wtf/ThreadSafeRefCounted.h> -
trunk/Source/JavaScriptCore/API/glib/JSCContext.cpp
r292487 r294017 22 22 23 23 #include "APICast.h" 24 #include "IntegrityInlines.h" 24 25 #include "JSCClassPrivate.h" 25 26 #include "JSCContextInternal.h" -
trunk/Source/JavaScriptCore/API/glib/JSCWrapperMap.cpp
r293324 r294017 22 22 23 23 #include "APICast.h" 24 #include "IntegrityInlines.h" 24 25 #include "JSAPIWrapperGlobalObject.h" 25 26 #include "JSAPIWrapperObject.h" -
trunk/Source/JavaScriptCore/API/tests/JSObjectGetProxyTargetTest.cpp
r273777 r294017 1 1 /* 2 * Copyright (C) 2017-20 18Apple Inc. All rights reserved.2 * Copyright (C) 2017-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 28 28 29 29 #include "APICast.h" 30 #include "IntegrityInlines.h" 30 31 #include "JSCInlines.h" 31 32 #include "JSObjectRefPrivate.h" -
trunk/Source/JavaScriptCore/ChangeLog
r294000 r294017 1 2022-05-10 Mark Lam <mark.lam@apple.com> 2 3 Add optional Integrity checks at JSC API boundaries. 4 https://bugs.webkit.org/show_bug.cgi?id=240264 5 6 Reviewed by Yusuke Suzuki. 7 8 1. Defined ENABLE_EXTRA_INTEGRITY_CHECKS in Integrity.h. JSC developers can enable 9 this for their local build if they want to enable more prolific Integrity audits. 10 This is disabled by default. 11 12 This feature is currently only supported for USE(JSVALUE64) targets. 13 14 The following changes only take effect if ENABLE(EXTRA_INTEGRITY_CHECKS) is enabled. 15 Otherwise, these are no-ops. 16 17 2. Added Integrity audits to all toJS and toRef conversion functions in APICast.h. 18 This will help us detect if bad values are passed across the API boundary. 19 20 3. Added some Integrity audits in JSValue.mm where the APICast ones were insufficient. 21 22 The following changes are in effect even when ENABLE(EXTRA_INTEGRITY_CHECKS) is 23 disabled. Some of these were made to support ENABLE(EXTRA_INTEGRITY_CHECKS), and 24 some are just clean up in related code that I had to touch along the way. 25 26 4. Moved isSanePointer() to Integrity.h so that it can be used in more places. 27 28 5. Changed VM registration with the VMInspector so that it's registered earlier 29 and removed later. Integrity audits may need to audit VM pointers while the 30 VM is being constructed and destructed. 31 32 6. Added VM::m_isInService to track when the VM is fully constructed or about to 33 be destructed since the VM is now registered with the VMInspector differently 34 (see (4) above). Applied this check in places that need it. 35 36 7. Fixed VMInspector::isValidExecutableMemory() to check the ExecutableAllocator 37 directly without iterating VMs (which is completely unnecessary). 38 39 8. Fixed VMInspector::isValidExecutableMemory() and VMInspector::codeBlockForMachinePC() 40 to use AdoptLock. This fixes a race condition where the lock can be contended 41 after ensureIsSafeToLock() succeeds. 42 43 9. Added VMInspector::isValidVM() to check if a VM pointer is registered or not. 44 VMInspector caches the most recently added or found VM so that isValidVM() 45 can just check the cache for its fast path. 46 47 10. Moved the implementation of VMInspector::verifyCell() to Integrity::analyzeCell() 48 and add more checks to it. VMInspector::verifyCell() now calls Integrity::verifyCell() 49 which uses Integrity::analyzeCell() to do the real cell analysis. 50 51 11. Also strengten Integrity::auditStructureID() so that it will check if a 52 Structure's memory has been released. This change is enabled on Debug builds 53 by default as well as when ENABLE(EXTRA_INTEGRITY_CHECKS). It is disabled 54 on Release builds. 55 56 * API/APICast.h: 57 (toJS): 58 (toJSForGC): 59 (uncheckedToJS): 60 (toRef): 61 (toGlobalRef): 62 * API/JSContext.mm: 63 * API/JSContextRef.cpp: 64 * API/JSScript.mm: 65 * API/JSValue.mm: 66 (ObjcContainerConvertor::convert): 67 (objectToValueWithoutCopy): 68 (objectToValue): 69 * API/JSVirtualMachine.mm: 70 * API/JSWeakPrivate.cpp: 71 * API/glib/JSCContext.cpp: 72 * API/glib/JSCWrapperMap.cpp: 73 * API/tests/JSObjectGetProxyTargetTest.cpp: 74 * bytecode/SpeculatedType.cpp: 75 (JSC::speculationFromCell): 76 (JSC::isSanePointer): Deleted. 77 * heap/HeapFinalizerCallback.cpp: 78 * heap/WeakSet.h: 79 * runtime/Structure.h: 80 * runtime/VM.cpp: 81 (JSC::VM::VM): 82 (JSC::VM::~VM): 83 * runtime/VM.h: 84 (JSC::VM::isInService const): 85 * tools/HeapVerifier.cpp: 86 (JSC::HeapVerifier::checkIfRecorded): 87 * tools/Integrity.cpp: 88 (JSC::Integrity::Random::reloadAndCheckShouldAuditSlow): 89 (JSC::Integrity::auditCellMinimallySlow): 90 (JSC::Integrity::doAudit): 91 (JSC::Integrity::Analyzer::analyzeVM): 92 (JSC::Integrity::Analyzer::analyzeCell): 93 (JSC::Integrity::doAuditSlow): 94 (JSC::Integrity::verifyCell): 95 (): Deleted. 96 (JSC::Integrity::auditCellFully): Deleted. 97 * tools/Integrity.h: 98 (JSC::isSanePointer): 99 (JSC::Integrity::auditCell): 100 (JSC::Integrity::audit): 101 * tools/IntegrityInlines.h: 102 (JSC::Integrity::auditCell): 103 (JSC::Integrity::auditCellFully): 104 (JSC::Integrity::auditStructureID): 105 (JSC::Integrity::doAudit): 106 * tools/VMInspector.cpp: 107 (JSC::VMInspector::add): 108 (JSC::VMInspector::remove): 109 (JSC::VMInspector::isValidVMSlow): 110 (JSC::VMInspector::dumpVMs): 111 (JSC::VMInspector::isValidExecutableMemory): 112 (JSC::VMInspector::codeBlockForMachinePC): 113 (JSC::ensureIsSafeToLock): Deleted. 114 * tools/VMInspector.h: 115 (JSC::VMInspector::isValidVM): 116 (): Deleted. 117 (JSC::VMInspector::unusedVerifier): Deleted. 118 * tools/VMInspectorInlines.h: 119 (JSC::VMInspector::verifyCell): 120 (JSC::VMInspector::verifyCellSize): Deleted. 121 1 122 2022-05-09 Ross Kirsling <ross.kirsling@sony.com> 2 123 -
trunk/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
r293657 r294017 1 1 /* 2 * Copyright (C) 2011-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2011-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 32 32 #include "DateInstance.h" 33 33 #include "DirectArguments.h" 34 #include "Integrity.h" 34 35 #include "JSArray.h" 35 36 #include "JSBigInt.h" … … 565 566 } 566 567 567 ALWAYS_INLINE static bool isSanePointer(const void* pointer)568 {569 // FIXME: rdar://69036888: remove this when no longer needed.570 #if CPU(ADDRESS64)571 uintptr_t pointerAsInt = bitwise_cast<uintptr_t>(pointer);572 uintptr_t canonicalPointerBits = pointerAsInt << (64 - OS_CONSTANT(EFFECTIVE_ADDRESS_WIDTH));573 uintptr_t nonCanonicalPointerBits = pointerAsInt >> OS_CONSTANT(EFFECTIVE_ADDRESS_WIDTH);574 return !nonCanonicalPointerBits && canonicalPointerBits;575 #else576 UNUSED_PARAM(pointer);577 return true;578 #endif579 }580 581 568 SpeculatedType speculationFromCell(JSCell* cell) 582 569 { 583 if (UNLIKELY(!isSanePointer(cell))) { 570 // FIXME: rdar://69036888: remove isSanePointer checks when no longer needed. 571 if (UNLIKELY(!Integrity::isSanePointer(cell))) { 584 572 ASSERT_NOT_REACHED(); 585 573 return SpecNone; … … 588 576 JSString* string = jsCast<JSString*>(cell); 589 577 if (const StringImpl* impl = string->tryGetValueImpl()) { 590 if (UNLIKELY(! isSanePointer(impl))) {578 if (UNLIKELY(!Integrity::isSanePointer(impl))) { 591 579 ASSERT_NOT_REACHED(); 592 580 return SpecNone; … … 599 587 // FIXME: rdar://69036888: undo this when no longer needed. 600 588 auto* structure = cell->structureID().tryDecode(); 601 if (UNLIKELY(! isSanePointer(structure))) {589 if (UNLIKELY(!Integrity::isSanePointer(structure))) { 602 590 ASSERT_NOT_REACHED(); 603 591 return SpecNone; -
trunk/Source/JavaScriptCore/heap/HeapFinalizerCallback.cpp
r216689 r294017 1 1 /* 2 * Copyright (C) 2017 Apple Inc. All rights reserved.2 * Copyright (C) 2017-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 28 28 29 29 #include "APICast.h" 30 #include "IntegrityInlines.h" 30 31 31 32 namespace JSC { -
trunk/Source/JavaScriptCore/heap/WeakSet.h
r273138 r294017 1 1 /* 2 * Copyright (C) 2012-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2012-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 35 35 class WeakImpl; 36 36 37 namespace Integrity { 38 class Analyzer; 39 } 40 37 41 class WeakSet : public BasicRawSentinelNode<WeakSet> { 38 42 friend class LLIntOffsetsExtractor; 43 friend class Integrity::Analyzer; 39 44 40 45 public: -
trunk/Source/JavaScriptCore/runtime/Structure.h
r293710 r294017 70 70 struct HashTableValue; 71 71 72 namespace Integrity { 73 class Analyzer; 74 } 75 72 76 // The out-of-line property storage capacity to use when first allocating out-of-line 73 77 // storage. Note that all objects start out without having any out-of-line storage; … … 991 995 friend class VMInspector; 992 996 friend class JSDollarVMHelper; 997 friend class Integrity::Analyzer; 993 998 }; 994 999 -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r292929 r294017 242 242 CRASH_WITH_INFO(0x4242424220202020, 0xbadbeef0badbeef, 0x1234123412341234, 0x1337133713371337); 243 243 244 VMInspector::instance().add(this); 245 244 246 interpreter = new Interpreter(*this); 245 247 updateSoftReservedZoneSize(Options::softReservedZoneSize()); … … 402 404 #endif 403 405 404 VMInspector::instance().add(this);405 406 406 if (!g_jscConfig.disabledFreezingForTesting) 407 407 Config::permanentlyFreeze(); 408 409 // We must set this at the end only after the VM is fully initialized. 410 WTF::storeStoreFence(); 411 m_isInService = true; 408 412 } 409 413 … … 428 432 m_watchdog->willDestroyVM(this); 429 433 m_traps.willDestroyVM(); 430 VMInspector::instance().remove(this); 434 m_isInService = false; 435 WTF::storeStoreFence(); 431 436 432 437 // Never GC, ever again. … … 456 461 457 462 JSRunLoopTimer::Manager::shared().unregisterVM(*this); 458 463 464 VMInspector::instance().remove(this); 465 459 466 delete interpreter; 460 467 #ifndef NDEBUG -
trunk/Source/JavaScriptCore/runtime/VM.h
r292795 r294017 347 347 GCClient::Heap clientHeap; 348 348 349 bool isInService() const { return m_isInService; } 350 349 351 const HeapCellType& cellHeapCellType() { return heap.cellHeapCellType; } 350 352 const JSDestructibleObjectHeapCellType& destructibleObjectHeapCellType() { return heap.destructibleObjectHeapCellType; }; … … 946 948 unsigned m_typeProfilerEnabledCount; 947 949 bool m_needToFirePrimitiveGigacageEnabled { false }; 950 bool m_isInService { false }; 948 951 Lock m_scratchBufferLock; 949 952 Vector<ScratchBuffer*> m_scratchBuffers; -
trunk/Source/JavaScriptCore/tools/HeapVerifier.cpp
r293779 r294017 444 444 Locker locker { AdoptLock, inspector.getLock() }; 445 445 inspector.iterate([&] (VM& vm) { 446 if (!vm.isInService()) 447 return IterationStatus::Continue; 448 446 449 if (!vm.heap.m_verifier) 447 450 return IterationStatus::Continue; -
trunk/Source/JavaScriptCore/tools/Integrity.cpp
r288815 r294017 1 1 /* 2 * Copyright (C) 2019-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 #include "Integrity.h" 28 28 29 #include "APICast.h" 30 #include "CellSize.h" 31 #include "IntegrityInlines.h" 32 #include "JSCast.h" 29 33 #include "JSCellInlines.h" 34 #include "JSGlobalObject.h" 30 35 #include "Options.h" 31 36 #include "VMInspectorInlines.h" … … 34 39 namespace Integrity { 35 40 36 namespace {37 constexpr bool verbose = false;41 namespace IntegrityInternal { 42 static constexpr bool verbose = false; 38 43 } 39 44 … … 49 54 if (!Options::randomIntegrityAuditRate()) { 50 55 m_triggerBits = 0; // Never trigger, and don't bother reloading. 51 if ( verbose)56 if (IntegrityInternal::verbose) 52 57 dataLogLn("disabled Integrity audits: trigger bits ", RawPointer(reinterpret_cast<void*>(m_triggerBits))); 53 58 return false; … … 62 67 m_triggerBits = m_triggerBits | (static_cast<uint64_t>(trigger) << i); 63 68 } 64 if ( verbose)69 if (IntegrityInternal::verbose) 65 70 dataLogLn("reloaded Integrity trigger bits ", RawPointer(reinterpret_cast<void*>(m_triggerBits))); 66 71 ASSERT(m_triggerBits >= (1ull << 63)); … … 68 73 } 69 74 70 void auditCellFully(VM& vm, JSCell* cell)71 {72 VMInspector::verifyCell<VMInspector::ReleaseAssert>(vm, cell);73 }74 75 75 void auditCellMinimallySlow(VM&, JSCell* cell) 76 76 { 77 77 if (Gigacage::contains(cell)) { 78 78 if (cell->type() != JSImmutableButterflyType) { 79 if ( verbose)80 dataLogLn(" Bad cell ", RawPointer(cell), " ", JSValue(cell));79 if (IntegrityInternal::verbose) 80 dataLogLn("Integrity ERROR: Bad cell ", RawPointer(cell), " ", JSValue(cell)); 81 81 CRASH(); 82 82 } … … 84 84 } 85 85 86 #if USE(JSVALUE64) 87 88 JSContextRef doAudit(JSContextRef ctx) 89 { 90 IA_ASSERT(ctx, "NULL JSContextRef"); 91 toJS(ctx); // toJS will trigger an audit. 92 return ctx; 93 } 94 95 JSGlobalContextRef doAudit(JSGlobalContextRef ctx) 96 { 97 IA_ASSERT(ctx, "NULL JSGlobalContextRef"); 98 toJS(ctx); // toJS will trigger an audit. 99 return ctx; 100 } 101 102 JSObjectRef doAudit(JSObjectRef objectRef) 103 { 104 if (!objectRef) 105 return objectRef; 106 toJS(objectRef); // toJS will trigger an audit. 107 return objectRef; 108 } 109 110 JSValueRef doAudit(JSValueRef valueRef) 111 { 112 #if CPU(ADDRESS64) 113 if (!valueRef) 114 return valueRef; 115 toJS(valueRef); // toJS will trigger an audit. 116 #endif 117 return valueRef; 118 } 119 120 JSValue doAudit(JSValue value) 121 { 122 if (value.isCell()) 123 doAudit(value.asCell()); 124 return value; 125 } 126 127 bool Analyzer::analyzeVM(VM& vm, Analyzer::Action action) 128 { 129 IA_ASSERT_WITH_ACTION(VMInspector::isValidVM(&vm), { 130 VMInspector::dumpVMs(); 131 if (action == Action::LogAndCrash) 132 RELEASE_ASSERT(VMInspector::isValidVM(&vm)); 133 else 134 return false; 135 }, "Invalid VM %p", &vm); 136 return true; 137 } 138 139 #if COMPILER(MSVC) || !VA_OPT_SUPPORTED 140 141 #define AUDIT_VERIFY(cond, format, ...) do { \ 142 IA_ASSERT_WITH_ACTION(cond, { \ 143 WTFLogAlways(" cell %p", cell); \ 144 if (action == Action::LogAndCrash) \ 145 RELEASE_ASSERT((cond), ##__VA_ARGS__); \ 146 else \ 147 return false; \ 148 }, format, ##__VA_ARGS__); \ 149 } while (false) 150 151 #else // not (COMPILER(MSVC) || !VA_OPT_SUPPORTED) 152 153 #define AUDIT_VERIFY(cond, format, ...) do { \ 154 IA_ASSERT_WITH_ACTION(cond, { \ 155 WTFLogAlways(" cell %p", cell); \ 156 if (action == Action::LogAndCrash) \ 157 RELEASE_ASSERT((cond) __VA_OPT__(,) __VA_ARGS__); \ 158 else \ 159 return false; \ 160 }, format __VA_OPT__(,) __VA_ARGS__); \ 161 } while (false) 162 163 #endif // COMPILER(MSVC) || !VA_OPT_SUPPORTED 164 165 bool Analyzer::analyzeCell(VM& vm, JSCell* cell, Analyzer::Action action) 166 { 167 AUDIT_VERIFY(isSanePointer(cell), "cell %p cell.type %d", cell, cell->type()); 168 169 size_t allocatorCellSize = 0; 170 if (cell->isPreciseAllocation()) { 171 PreciseAllocation& preciseAllocation = cell->preciseAllocation(); 172 AUDIT_VERIFY(&preciseAllocation.vm() == &vm, 173 "cell %p cell.type %d preciseAllocation.vm %p vm %p", cell, cell->type(), &preciseAllocation.vm(), &vm); 174 175 bool isValidPreciseAllocation = false; 176 for (auto* i : vm.heap.objectSpace().preciseAllocations()) { 177 if (i == &preciseAllocation) { 178 isValidPreciseAllocation = true; 179 break; 180 } 181 } 182 AUDIT_VERIFY(isValidPreciseAllocation, "cell %p cell.type %d", cell, cell->type()); 183 184 allocatorCellSize = preciseAllocation.cellSize(); 185 } else { 186 MarkedBlock& block = cell->markedBlock(); 187 MarkedBlock::Handle& blockHandle = block.handle(); 188 AUDIT_VERIFY(&block.vm() == &vm, 189 "cell %p cell.type %d markedBlock.vm %p vm %p", cell, cell->type(), &block.vm(), &vm); 190 191 uintptr_t blockStartAddress = reinterpret_cast<uintptr_t>(blockHandle.start()); 192 AUDIT_VERIFY(blockHandle.contains(cell), 193 "cell %p cell.type %d markedBlock.start %p markedBlock.end %p", cell, cell->type(), blockHandle.start(), blockHandle.end()); 194 195 uintptr_t cellAddress = reinterpret_cast<uintptr_t>(cell); 196 uintptr_t cellOffset = cellAddress - blockStartAddress; 197 allocatorCellSize = block.cellSize(); 198 bool cellIsProperlyAligned = !(cellOffset % allocatorCellSize); 199 AUDIT_VERIFY(cellIsProperlyAligned, 200 "cell %p cell.type %d allocator.cellSize %zu", cell, cell->type(), allocatorCellSize); 201 } 202 203 JSType cellType = cell->type(); 204 if (cell->type() != JSImmutableButterflyType) 205 AUDIT_VERIFY(!Gigacage::contains(cell), "cell %p cell.type %d", cell, cellType); 206 207 WeakSet& weakSet = cell->cellContainer().weakSet(); 208 AUDIT_VERIFY(!weakSet.m_allocator || isSanePointer(weakSet.m_allocator), 209 "cell %p cell.type %d weakSet.allocator %p", cell, cell->type(), weakSet.m_allocator); 210 AUDIT_VERIFY(!weakSet.m_nextAllocator || isSanePointer(weakSet.m_nextAllocator), 211 "cell %p cell.type %d weakSet.allocator %p", cell, cell->type(), weakSet.m_nextAllocator); 212 213 // If we're currently destructing the cell, then we can't rely on its 214 // structure being good. Skip the following tests which rely on structure. 215 if (vm.currentlyDestructingCallbackObject == cell) 216 return true; 217 218 auto structureID = cell->structureID(); 219 220 Structure* structure = structureID.tryDecode(); 221 AUDIT_VERIFY(structure, 222 "cell %p cell.type %d structureID.bits 0x%x", cell, cellType, structureID.bits()); 223 if (action == Analyzer::Action::LogAndCrash) { 224 // structure should be pointing to readable memory. Force a read. 225 WTF::opaque(*bitwise_cast<uintptr_t*>(structure)); 226 } 227 228 const ClassInfo* classInfo = structure->classInfoForCells(); 229 AUDIT_VERIFY(cellType == structure->m_blob.type(), 230 "cell %p cell.type %d structureBlob.type %d", cell, cellType, structure->m_blob.type()); 231 232 size_t size = cellSize(cell); 233 AUDIT_VERIFY(size <= allocatorCellSize, 234 "cell %p cell.type %d cell.size %zu allocator.cellSize %zu, classInfo.cellSize %u", cell, cellType, size, allocatorCellSize, classInfo->staticClassSize); 235 if (isDynamicallySizedType(cellType)) { 236 AUDIT_VERIFY(size >= classInfo->staticClassSize, 237 "cell %p cell.type %d cell.size %zu classInfo.cellSize %u", cell, cellType, size, classInfo->staticClassSize); 238 } 239 240 if (cell->isObject()) { 241 AUDIT_VERIFY(jsDynamicCast<JSObject*>(cell), 242 "cell %p cell.type %d", cell, cell->type()); 243 244 if (Gigacage::isEnabled(Gigacage::JSValue)) { 245 JSObject* object = bitwise_cast<JSObject*>(cell); 246 const Butterfly* butterfly = object->butterfly(); 247 AUDIT_VERIFY(!butterfly || Gigacage::isCaged(Gigacage::JSValue, butterfly), 248 "cell %p cell.type %d butterfly %p", cell, cell->type(), butterfly); 249 } 250 } 251 252 return true; 253 } 254 255 bool Analyzer::analyzeCell(JSCell* cell, Analyzer::Action action) 256 { 257 if (!cell) 258 return cell; 259 260 JSValue value = JSValue::decode(static_cast<EncodedJSValue>(bitwise_cast<uintptr_t>(cell))); 261 AUDIT_VERIFY(value.isCell(), "Invalid cell address: cell %p", cell); 262 263 VM& vm = cell->vm(); 264 analyzeVM(vm, action); 265 return analyzeCell(vm, cell, action); 266 } 267 268 #undef AUDIT_VERIFY 269 270 VM* doAuditSlow(VM* vm) 271 { 272 Analyzer::analyzeVM(*vm, Analyzer::Action::LogAndCrash); 273 return vm; 274 } 275 276 JSCell* doAudit(JSCell* cell) 277 { 278 Analyzer::analyzeCell(cell, Analyzer::Action::LogAndCrash); 279 return cell; 280 } 281 282 JSCell* doAudit(VM& vm, JSCell* cell) 283 { 284 if (!cell) 285 return cell; 286 Analyzer::analyzeCell(vm, cell, Analyzer::Action::LogAndCrash); 287 return cell; 288 } 289 290 bool verifyCell(JSCell* cell) 291 { 292 bool valid = Analyzer::analyzeCell(cell, Analyzer::Action::LogOnly); 293 WTFLogAlways("Cell %p is %s", cell, valid ? "VALID" : "INVALID"); 294 return valid; 295 } 296 297 bool verifyCell(VM& vm, JSCell* cell) 298 { 299 bool valid = Analyzer::analyzeCell(vm, cell, Analyzer::Action::LogOnly); 300 WTFLogAlways("Cell %p is %s", cell, valid ? "VALID" : "INVALID"); 301 return valid; 302 } 303 304 JSObject* doAudit(JSObject* object) 305 { 306 if (!object) 307 return object; 308 JSCell* cell = doAudit(reinterpret_cast<JSCell*>(object)); 309 IA_ASSERT(cell->isObject(), "Invalid JSObject %p", object); 310 return object; 311 } 312 313 JSGlobalObject* doAudit(JSGlobalObject* globalObject) 314 { 315 doAudit(reinterpret_cast<JSCell*>(globalObject)); 316 IA_ASSERT(globalObject->isGlobalObject(), "Invalid JSGlobalObject %p", globalObject); 317 return globalObject; 318 } 319 320 #endif // USE(JSVALUE64) 321 86 322 } // namespace Integrity 87 323 } // namespace JSC -
trunk/Source/JavaScriptCore/tools/Integrity.h
r288815 r294017 1 1 /* 2 * Copyright (C) 2019-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 26 26 #pragma once 27 27 28 #include "JSCJSValue.h" 29 #include "StructureID.h" 30 #include <wtf/Gigacage.h> 28 #include <wtf/Assertions.h> 31 29 #include <wtf/Lock.h> 32 30 31 #if OS(DARWIN) 32 #include <mach/vm_param.h> 33 #endif 34 35 #if USE(JSVALUE32) 36 #define ENABLE_EXTRA_INTEGRITY_CHECKS 0 // Not supported. 37 #else 38 // Force ENABLE_EXTRA_INTEGRITY_CHECKS to 1 for your local build if you want 39 // more prolific audits to be enabled. 40 #define ENABLE_EXTRA_INTEGRITY_CHECKS 0 41 #endif 42 43 // From API/JSBase.h 44 typedef const struct OpaqueJSContextGroup* JSContextGroupRef; 45 typedef const struct OpaqueJSContext* JSContextRef; 46 typedef struct OpaqueJSContext* JSGlobalContextRef; 47 typedef struct OpaqueJSPropertyNameAccumulator* JSPropertyNameAccumulatorRef; 48 typedef const struct OpaqueJSValue* JSValueRef; 49 typedef struct OpaqueJSValue* JSObjectRef; 50 33 51 namespace JSC { 34 52 35 53 class JSCell; 54 class JSGlobalObject; 55 class JSObject; 56 class JSValue; 57 class Structure; 58 class StructureID; 36 59 class VM; 37 60 … … 68 91 }; 69 92 93 ALWAYS_INLINE static bool isSanePointer(const void* pointer) 94 { 95 #if CPU(ADDRESS64) 96 uintptr_t pointerAsInt = bitwise_cast<uintptr_t>(pointer); 97 uintptr_t canonicalPointerBits = pointerAsInt << (64 - OS_CONSTANT(EFFECTIVE_ADDRESS_WIDTH)); 98 uintptr_t nonCanonicalPointerBits = pointerAsInt >> OS_CONSTANT(EFFECTIVE_ADDRESS_WIDTH); 99 return !nonCanonicalPointerBits && canonicalPointerBits; 100 #else 101 UNUSED_PARAM(pointer); 102 return true; 103 #endif 104 } 105 106 #if USE(JSVALUE64) 107 108 class Analyzer { 109 public: 110 enum Action { LogOnly, LogAndCrash }; 111 112 static bool analyzeVM(VM&, Action); 113 static bool analyzeCell(VM&, JSCell*, Action); 114 static bool analyzeCell(JSCell*, Action); 115 }; 116 117 JS_EXPORT_PRIVATE JSContextRef doAudit(JSContextRef); 118 JS_EXPORT_PRIVATE JSGlobalContextRef doAudit(JSGlobalContextRef); 119 JS_EXPORT_PRIVATE JSObjectRef doAudit(JSObjectRef); 120 JS_EXPORT_PRIVATE JSValueRef doAudit(JSValueRef); 121 122 JS_EXPORT_PRIVATE JSValue doAudit(JSValue); 123 JS_EXPORT_PRIVATE JSCell* doAudit(JSCell*); 124 JS_EXPORT_PRIVATE JSCell* doAudit(VM&, JSCell*); 125 JS_EXPORT_PRIVATE JSObject* doAudit(JSObject*); 126 JS_EXPORT_PRIVATE JSGlobalObject* doAudit(JSGlobalObject*); 127 128 VM* doAudit(VM*); // see IntegrityInlines.h 129 130 // These are used for debugging queries, and will not crash. 131 JS_EXPORT_PRIVATE bool verifyCell(JSCell*); 132 JS_EXPORT_PRIVATE bool verifyCell(VM&, JSCell*); 133 134 #endif // USE(JSVALUE64) 135 70 136 ALWAYS_INLINE void auditCellRandomly(VM&, JSCell*); 71 137 ALWAYS_INLINE void auditCellMinimally(VM&, JSCell*); 72 138 JS_EXPORT_PRIVATE void auditCellMinimallySlow(VM&, JSCell*); 73 JS_EXPORT_PRIVATE void auditCellFully(VM&, JSCell*);139 ALWAYS_INLINE void auditCellFully(VM&, JSCell*); 74 140 75 141 template<AuditLevel = AuditLevel::Random, typename T> … … 79 145 ALWAYS_INLINE void auditCell(VM& vm, JSCell* cell) 80 146 { 81 switch (auditLevel) { 82 case AuditLevel::None: 147 static_assert(auditLevel == AuditLevel::None || auditLevel == AuditLevel::Minimal || auditLevel == AuditLevel::Full || auditLevel == AuditLevel::Random); 148 149 UNUSED_PARAM(vm); 150 UNUSED_PARAM(cell); 151 if constexpr (auditLevel == AuditLevel::None) 83 152 return; 84 case AuditLevel::Minimal:153 if constexpr (auditLevel == AuditLevel::Minimal) 85 154 return auditCellMinimally(vm, cell); 86 case AuditLevel::Full:155 if constexpr (auditLevel == AuditLevel::Full) 87 156 return auditCellFully(vm, cell); 88 case AuditLevel::Random:157 if constexpr (auditLevel == AuditLevel::Random) 89 158 return auditCellRandomly(vm, cell); 90 }91 159 } 92 160 93 161 template<AuditLevel auditLevel = DefaultAuditLevel> 94 ALWAYS_INLINE void auditCell(VM& vm, JSValue value) 95 { 96 if (auditLevel == AuditLevel::None) 97 return; 98 99 if (value.isCell()) 100 auditCell<auditLevel>(vm, value.asCell()); 101 } 162 ALWAYS_INLINE void auditCell(VM&, JSValue); 102 163 103 164 ALWAYS_INLINE void auditStructureID(StructureID); 104 165 166 #if ENABLE(EXTRA_INTEGRITY_CHECKS) && USE(JSVALUE64) 167 template<typename T> ALWAYS_INLINE T audit(T value) { return doAudit(value); } 168 #else 169 template<typename T> ALWAYS_INLINE T audit(T value) { return value; } 170 #endif 171 172 #if COMPILER(MSVC) || !VA_OPT_SUPPORTED 173 174 #define IA_LOG(assertion, format, ...) do { \ 175 WTFLogAlways("Integrity ERROR: %s @ %s:%d\n", #assertion, __FILE__, __LINE__); \ 176 WTFLogAlways(" " format, ##__VA_ARGS__); \ 177 } while (false) 178 179 #define IA_ASSERT_WITH_ACTION(assertion, action, ...) do { \ 180 if (UNLIKELY(!(assertion))) { \ 181 IA_LOG(assertion, __VA_ARGS__); \ 182 WTFReportBacktraceWithPrefix(" "); \ 183 action; \ 184 } \ 185 } while (false) 186 187 #define IA_ASSERT(assertion, ...) \ 188 IA_ASSERT_WITH_ACTION(assertion, { \ 189 RELEASE_ASSERT((assertion), ##__VA_ARGS__); \ 190 }, ## __VA_ARGS__) 191 192 #else // not (COMPILER(MSVC) || !VA_OPT_SUPPORTED) 193 194 #define IA_LOG(assertion, format, ...) do { \ 195 WTFLogAlways("Integrity ERROR: %s @ %s:%d\n", #assertion, __FILE__, __LINE__); \ 196 WTFLogAlways(" " format __VA_OPT__(,) __VA_ARGS__); \ 197 } while (false) 198 199 #define IA_ASSERT_WITH_ACTION(assertion, action, ...) do { \ 200 if (UNLIKELY(!(assertion))) { \ 201 IA_LOG(assertion, __VA_ARGS__); \ 202 WTFReportBacktraceWithPrefix(" "); \ 203 action; \ 204 } \ 205 } while (false) 206 207 #define IA_ASSERT(assertion, ...) \ 208 IA_ASSERT_WITH_ACTION(assertion, { \ 209 RELEASE_ASSERT((assertion) __VA_OPT__(,) __VA_ARGS__); \ 210 } __VA_OPT__(,) __VA_ARGS__) 211 212 #endif // COMPILER(MSVC) || !VA_OPT_SUPPORTED 213 105 214 } // namespace Integrity 106 215 -
trunk/Source/JavaScriptCore/tools/IntegrityInlines.h
r293746 r294017 1 1 /* 2 * Copyright (C) 2019-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 28 28 #include "Integrity.h" 29 #include "JSCJSValue.h" 30 #include "StructureID.h" 29 31 #include "VM.h" 32 #include "VMInspector.h" 33 #include <wtf/Atomics.h> 34 #include <wtf/Gigacage.h> 30 35 31 36 namespace JSC { … … 62 67 } 63 68 69 template<AuditLevel auditLevel> 70 ALWAYS_INLINE void auditCell(VM& vm, JSValue value) 71 { 72 if constexpr (auditLevel == AuditLevel::None) 73 return; 74 75 if (value.isCell()) 76 auditCell<auditLevel>(vm, value.asCell()); 77 } 78 64 79 ALWAYS_INLINE void auditCellMinimally(VM& vm, JSCell* cell) 65 80 { … … 74 89 } 75 90 91 ALWAYS_INLINE void auditCellFully(VM& vm, JSCell* cell) 92 { 93 #if USE(JSVALUE64) 94 doAudit(vm, cell); 95 #else 96 auditCellMinimally(vm, cell); 97 #endif 98 } 76 99 77 100 ALWAYS_INLINE void auditStructureID(StructureID structureID) … … 81 104 ASSERT(static_cast<uintptr_t>(structureID.bits()) <= structureHeapAddressSize + StructureID::nukedStructureIDBit); 82 105 #endif 106 #if ENABLE(EXTRA_INTEGRITY_CHECKS) || ASSERT_ENABLED 107 Structure* structure = structureID.tryDecode(); 108 IA_ASSERT(structure, "structureID.bits 0x%x", structureID.bits()); 109 // structure should be pointing to readable memory. Force a read. 110 WTF::opaque(*bitwise_cast<uintptr_t*>(structure)); 111 #endif 83 112 } 113 114 #if USE(JSVALUE64) 115 116 JS_EXPORT_PRIVATE VM* doAuditSlow(VM*); 117 118 ALWAYS_INLINE VM* doAudit(VM* vm) 119 { 120 if (UNLIKELY(!VMInspector::isValidVM(vm))) 121 return doAuditSlow(vm); 122 return vm; 123 } 124 125 #endif // USE(JSVALUE64) 84 126 85 127 } // namespace Integrity -
trunk/Source/JavaScriptCore/tools/VMInspector.cpp
r293779 r294017 39 39 namespace JSC { 40 40 41 VM* VMInspector::m_recentVM { nullptr }; 42 41 43 VMInspector& VMInspector::instance() 42 44 { … … 52 54 { 53 55 Locker locker { m_lock }; 56 m_recentVM = vm; 54 57 m_vmList.append(vm); 55 58 } … … 58 61 { 59 62 Locker locker { m_lock }; 63 if (m_recentVM == vm) 64 m_recentVM = nullptr; 60 65 m_vmList.remove(vm); 61 66 } 62 67 63 68 #if ENABLE(JIT) 64 static bool ensureIsSafeToLock(Lock& lock) 69 static bool ensureIsSafeToLock(Lock& lock) WTF_IGNORES_THREAD_SAFETY_ANALYSIS 65 70 { 66 71 static constexpr unsigned maxRetries = 2; 67 72 unsigned tryCount = 0; 68 73 while (tryCount++ <= maxRetries) { 69 if (lock.tryLock()) { 70 lock.unlock(); 74 if (lock.tryLock()) 71 75 return true; 72 }73 76 } 74 77 return false; 75 78 } 76 79 #endif // ENABLE(JIT) 80 81 bool VMInspector::isValidVMSlow(VM* vm) 82 { 83 bool found = false; 84 forEachVM([&] (VM& nextVM) { 85 if (vm == &nextVM) { 86 m_recentVM = vm; 87 found = true; 88 return IterationStatus::Done; 89 } 90 return IterationStatus::Continue; 91 }); 92 return found; 93 } 94 95 void VMInspector::dumpVMs() 96 { 97 unsigned i = 0; 98 WTFLogAlways("Registered VMs:"); 99 forEachVM([&] (VM& nextVM) { 100 WTFLogAlways(" [%u] VM %p", i++, &nextVM); 101 return IterationStatus::Continue; 102 }); 103 } 77 104 78 105 void VMInspector::forEachVM(Function<IterationStatus(VM&)>&& func) … … 83 110 } 84 111 85 auto VMInspector::isValidExecutableMemory(void* machinePC) -> Expected<bool, Error>112 WTF_IGNORES_THREAD_SAFETY_ANALYSIS auto VMInspector::isValidExecutableMemory(void* machinePC) -> Expected<bool, Error> 86 113 { 87 114 #if ENABLE(JIT) 88 bool found = false; 89 bool hasTimeout = false; 90 iterate([&] (VM&) -> IterationStatus { 91 auto& allocator = ExecutableAllocator::singleton(); 92 auto& lock = allocator.getLock(); 93 94 bool isSafeToLock = ensureIsSafeToLock(lock); 95 if (!isSafeToLock) { 96 hasTimeout = true; 97 return IterationStatus::Continue; // Skip this VM. 98 } 99 100 Locker executableAllocatorLocker { lock }; 101 if (allocator.isValidExecutableMemory(executableAllocatorLocker, machinePC)) { 102 found = true; 103 return IterationStatus::Done; 104 } 105 return IterationStatus::Continue; 106 }); 107 108 if (!found && hasTimeout) 115 auto& allocator = ExecutableAllocator::singleton(); 116 auto& lock = allocator.getLock(); 117 118 bool isSafeToLock = ensureIsSafeToLock(lock); 119 if (!isSafeToLock) 109 120 return makeUnexpected(Error::TimedOut); 110 return found; 121 122 Locker executableAllocatorLocker { AdoptLock, lock }; 123 if (allocator.isValidExecutableMemory(executableAllocatorLocker, machinePC)) 124 return true; 125 126 return false; 111 127 #else 112 128 UNUSED_PARAM(machinePC); … … 120 136 CodeBlock* codeBlock = nullptr; 121 137 bool hasTimeout = false; 122 iterate([&] (VM& vm) { 138 iterate([&] (VM& vm) WTF_IGNORES_THREAD_SAFETY_ANALYSIS { 139 if (!vm.isInService()) 140 return IterationStatus::Continue; 141 123 142 if (!vm.currentThreadIsHoldingAPILock()) 124 143 return IterationStatus::Continue; … … 142 161 } 143 162 144 Locker locker { codeBlockSetLock };163 Locker locker { AdoptLock, codeBlockSetLock }; 145 164 vm.heap.forEachCodeBlockIgnoringJITPlans(locker, [&] (CodeBlock* cb) { 146 165 JITCode* jitCode = cb->jitCode().get(); -
trunk/Source/JavaScriptCore/tools/VMInspector.h
r293779 r294017 49 49 void add(VM*); 50 50 void remove(VM*); 51 ALWAYS_INLINE static bool isValidVM(VM* vm) 52 { 53 return vm == m_recentVM ? true : isValidVMSlow(vm); 54 } 51 55 52 56 Lock& getLock() WTF_RETURNS_LOCK(m_lock) { return m_lock; } … … 62 66 63 67 JS_EXPORT_PRIVATE static void forEachVM(Function<IterationStatus(VM&)>&&); 68 JS_EXPORT_PRIVATE static void dumpVMs(); 64 69 65 70 Expected<bool, Error> isValidExecutableMemory(void*) WTF_REQUIRES_LOCK(m_lock); … … 81 86 JS_EXPORT_PRIVATE static void dumpSubspaceHashes(VM*); 82 87 83 enum VerifierAction { ReleaseAssert, Custom }; 84 85 using VerifyFunctor = bool(bool condition, const char* description, ...); 86 static bool unusedVerifier(bool, const char*, ...) { return false; } 87 88 template<VerifierAction, VerifyFunctor = unusedVerifier> 89 static bool verifyCellSize(JSCell*, size_t allocatorCellSize); 90 91 template<VerifierAction, VerifyFunctor = unusedVerifier> 88 #if USE(JSVALUE64) 92 89 static bool verifyCell(VM&, JSCell*); 90 #endif 93 91 94 92 private: 93 JS_EXPORT_PRIVATE static bool isValidVMSlow(VM*); 94 95 95 Lock m_lock; 96 96 DoublyLinkedList<VM> m_vmList WTF_GUARDED_BY_LOCK(m_lock); 97 JS_EXPORT_PRIVATE static VM* m_recentVM; 97 98 }; 98 99 -
trunk/Source/JavaScriptCore/tools/VMInspectorInlines.h
r292929 r294017 1 1 /* 2 * Copyright (C) 2019 Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 26 26 #pragma once 27 27 28 #include " CellSize.h"28 #include "Integrity.h" 29 29 #include "VMInspector.h" 30 #include <wtf/Assertions.h>31 30 32 31 namespace JSC { 33 32 34 #define AUDIT_CONDITION(x) (x), #x 35 #define AUDIT_VERIFY(action, verifier, cond, ...) do { \ 36 if (action == VerifierAction::ReleaseAssert) \ 37 RELEASE_ASSERT(cond, __VA_ARGS__); \ 38 else if (!verifier(AUDIT_CONDITION(cond), __VA_ARGS__)) \ 39 return false; \ 40 } while (false) 41 42 template<VMInspector::VerifierAction action, VMInspector::VerifyFunctor verifier> 43 bool VMInspector::verifyCellSize(JSCell* cell, size_t allocatorCellSize) 33 #if USE(JSVALUE64) 34 ALWAYS_INLINE bool VMInspector::verifyCell(VM& vm, JSCell* cell) 44 35 { 45 Structure* structure = cell->structure(); 46 const ClassInfo* classInfo = structure->classInfoForCells(); 47 JSType cellType = cell->type(); 48 AUDIT_VERIFY(action, verifier, cellType == structure->m_blob.type(), cell, cellType, structure->m_blob.type()); 49 50 size_t size = cellSize(cell); 51 AUDIT_VERIFY(action, verifier, size <= allocatorCellSize, cell, cellType, size, allocatorCellSize, classInfo->staticClassSize); 52 if (isDynamicallySizedType(cellType)) 53 AUDIT_VERIFY(action, verifier, size >= classInfo->staticClassSize, cell, cellType, size, classInfo->staticClassSize); 54 55 return true; 36 return Integrity::verifyCell(vm, cell); 56 37 } 57 58 template<VMInspector::VerifierAction action, VMInspector::VerifyFunctor verifier> 59 bool VMInspector::verifyCell(VM& vm, JSCell* cell) 60 { 61 size_t allocatorCellSize = 0; 62 if (cell->isPreciseAllocation()) { 63 PreciseAllocation& preciseAllocation = cell->preciseAllocation(); 64 AUDIT_VERIFY(action, verifier, &preciseAllocation.vm() == &vm, cell, cell->type(), &preciseAllocation.vm(), &vm); 65 66 bool isValidPreciseAllocation = false; 67 for (auto* i : vm.heap.objectSpace().preciseAllocations()) { 68 if (i == &preciseAllocation) { 69 isValidPreciseAllocation = true; 70 break; 71 } 72 } 73 AUDIT_VERIFY(action, verifier, isValidPreciseAllocation, cell, cell->type()); 74 75 allocatorCellSize = preciseAllocation.cellSize(); 76 } else { 77 MarkedBlock& block = cell->markedBlock(); 78 MarkedBlock::Handle& blockHandle = block.handle(); 79 AUDIT_VERIFY(action, verifier, &block.vm() == &vm, cell, cell->type(), &block.vm(), &vm); 80 81 uintptr_t blockStartAddress = reinterpret_cast<uintptr_t>(blockHandle.start()); 82 AUDIT_VERIFY(action, verifier, blockHandle.contains(cell), cell, cell->type(), blockStartAddress, blockHandle.end()); 83 84 uintptr_t cellAddress = reinterpret_cast<uintptr_t>(cell); 85 uintptr_t cellOffset = cellAddress - blockStartAddress; 86 allocatorCellSize = block.cellSize(); 87 bool cellIsProperlyAligned = !(cellOffset % allocatorCellSize); 88 AUDIT_VERIFY(action, verifier, cellIsProperlyAligned, cell, cell->type(), allocatorCellSize); 89 } 90 91 auto cellType = cell->type(); 92 if (cell->type() != JSImmutableButterflyType) 93 AUDIT_VERIFY(action, verifier, !Gigacage::contains(cell), cell, cellType); 94 95 if (!verifyCellSize<action, verifier>(cell, allocatorCellSize)) 96 return false; 97 98 if (Gigacage::isEnabled(Gigacage::JSValue) && cell->isObject()) { 99 JSObject* object = asObject(cell); 100 const Butterfly* butterfly = object->butterfly(); 101 AUDIT_VERIFY(action, verifier, !butterfly || Gigacage::isCaged(Gigacage::JSValue, butterfly), cell, cell->type(), butterfly); 102 } 103 104 return true; 105 } 106 107 #undef AUDIT_VERIFY 108 #undef AUDIT_CONDITION 38 #endif 109 39 110 40 } // namespace JSC
Note: See TracChangeset
for help on using the changeset viewer.