1/*
2 * Copyright (C) 2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "CellSize.h"
29#include "VMInspector.h"
30#include <wtf/Assertions.h>
31
32namespace JSC {
33
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
42template<VMInspector::VerifierAction action, VMInspector::VerifyFunctor verifier>
43bool VMInspector::verifyCellSize(VM& vm, JSCell* cell, size_t allocatorCellSize)
44{
45 Structure* structure = cell->structure(vm);
46 const ClassInfo* classInfo = structure->classInfo();
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(vm, 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;
56}
57
58template<VMInspector::VerifierAction action, VMInspector::VerifyFunctor verifier>
59bool 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>(vm, 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
109
110} // namespace JSC
111