1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/core/SkDescriptor.h"
9
10 #include "include/core/SkTypes.h"
11 #include "include/private/base/SkAlign.h"
12 #include "include/private/base/SkTemplates.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/core/SkChecksum.h"
15 #include "src/core/SkReadBuffer.h"
16 #include "src/core/SkWriteBuffer.h"
17
18 #include <cstring>
19
Alloc(size_t length)20 std::unique_ptr<SkDescriptor> SkDescriptor::Alloc(size_t length) {
21 SkASSERT(length >= sizeof(SkDescriptor) && SkAlign4(length) == length);
22 void* allocation = ::operator new(length);
23 return std::unique_ptr<SkDescriptor>(new (allocation) SkDescriptor{});
24 }
25
operator delete(void * p)26 void SkDescriptor::operator delete(void* p) { ::operator delete(p); }
operator new(size_t)27 void* SkDescriptor::operator new(size_t) {
28 SK_ABORT("Descriptors are created with placement new.");
29 }
30
flatten(SkWriteBuffer & buffer) const31 void SkDescriptor::flatten(SkWriteBuffer& buffer) const {
32 buffer.writePad32(static_cast<const void*>(this), this->fLength);
33 }
34
addEntry(uint32_t tag,size_t length,const void * data)35 void* SkDescriptor::addEntry(uint32_t tag, size_t length, const void* data) {
36 SkASSERT(tag);
37 SkASSERT(SkAlign4(length) == length);
38 SkASSERT(this->findEntry(tag, nullptr) == nullptr);
39
40 Entry* entry = (Entry*)((char*)this + fLength);
41 entry->fTag = tag;
42 entry->fLen = SkToU32(length);
43 if (data) {
44 memcpy(entry + 1, data, length);
45 }
46
47 fCount += 1;
48 fLength = SkToU32(fLength + sizeof(Entry) + length);
49 return (entry + 1); // return its data
50 }
51
computeChecksum()52 void SkDescriptor::computeChecksum() {
53 fChecksum = SkDescriptor::ComputeChecksum(this);
54 }
55
findEntry(uint32_t tag,uint32_t * length) const56 const void* SkDescriptor::findEntry(uint32_t tag, uint32_t* length) const {
57 const Entry* entry = (const Entry*)(this + 1);
58 int count = fCount;
59
60 while (--count >= 0) {
61 if (entry->fTag == tag) {
62 if (length) {
63 *length = entry->fLen;
64 }
65 return entry + 1;
66 }
67 entry = (const Entry*)((const char*)(entry + 1) + entry->fLen);
68 }
69 return nullptr;
70 }
71
copy() const72 std::unique_ptr<SkDescriptor> SkDescriptor::copy() const {
73 std::unique_ptr<SkDescriptor> desc = SkDescriptor::Alloc(fLength);
74 memcpy(desc.get(), this, fLength);
75 return desc;
76 }
77
operator ==(const SkDescriptor & other) const78 bool SkDescriptor::operator==(const SkDescriptor& other) const {
79 // the first value we should look at is the checksum, so this loop
80 // should terminate early if they descriptors are different.
81 // NOTE: if we wrote a sentinel value at the end of each, we could
82 // remove the aa < stop test in the loop...
83 const uint32_t* aa = (const uint32_t*)this;
84 const uint32_t* bb = (const uint32_t*)&other;
85 const uint32_t* stop = (const uint32_t*)((const char*)aa + fLength);
86 do {
87 if (*aa++ != *bb++)
88 return false;
89 } while (aa < stop);
90 return true;
91 }
92
dumpRec() const93 SkString SkDescriptor::dumpRec() const {
94 const SkScalerContextRec* rec = static_cast<const SkScalerContextRec*>(
95 this->findEntry(kRec_SkDescriptorTag, nullptr));
96
97 SkString result;
98 result.appendf(" Checksum: %x\n", fChecksum);
99 if (rec != nullptr) {
100 result.append(rec->dump());
101 }
102 return result;
103 }
104
ComputeChecksum(const SkDescriptor * desc)105 uint32_t SkDescriptor::ComputeChecksum(const SkDescriptor* desc) {
106 const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field
107 size_t len = desc->fLength - sizeof(uint32_t);
108 return SkChecksum::Hash32(ptr, len);
109 }
110
isValid() const111 bool SkDescriptor::isValid() const {
112 uint32_t count = fCount;
113 size_t lengthRemaining = this->fLength;
114 if (lengthRemaining < sizeof(SkDescriptor)) {
115 return false;
116 }
117 lengthRemaining -= sizeof(SkDescriptor);
118 size_t offset = sizeof(SkDescriptor);
119
120 while (lengthRemaining > 0 && count > 0) {
121 if (lengthRemaining < sizeof(Entry)) {
122 return false;
123 }
124 lengthRemaining -= sizeof(Entry);
125
126 const Entry* entry = (const Entry*)(reinterpret_cast<const char*>(this) + offset);
127
128 if (lengthRemaining < entry->fLen) {
129 return false;
130 }
131 lengthRemaining -= entry->fLen;
132
133 // rec tags are always a known size.
134 if (entry->fTag == kRec_SkDescriptorTag && entry->fLen != sizeof(SkScalerContextRec)) {
135 return false;
136 }
137
138 offset += sizeof(Entry) + entry->fLen;
139 count--;
140 }
141 return lengthRemaining == 0 && count == 0;
142 }
143
144 SkAutoDescriptor::SkAutoDescriptor() = default;
SkAutoDescriptor(size_t size)145 SkAutoDescriptor::SkAutoDescriptor(size_t size) { this->reset(size); }
SkAutoDescriptor(const SkDescriptor & desc)146 SkAutoDescriptor::SkAutoDescriptor(const SkDescriptor& desc) { this->reset(desc); }
SkAutoDescriptor(const SkAutoDescriptor & that)147 SkAutoDescriptor::SkAutoDescriptor(const SkAutoDescriptor& that) {
148 this->reset(*that.getDesc());
149 }
operator =(const SkAutoDescriptor & that)150 SkAutoDescriptor& SkAutoDescriptor::operator=(const SkAutoDescriptor& that) {
151 this->reset(*that.getDesc());
152 return *this;
153 }
SkAutoDescriptor(SkAutoDescriptor && that)154 SkAutoDescriptor::SkAutoDescriptor(SkAutoDescriptor&& that) {
155 if (that.fDesc == (SkDescriptor*)&that.fStorage) {
156 this->reset(*that.getDesc());
157 } else {
158 fDesc = that.fDesc;
159 that.fDesc = nullptr;
160 }
161 }
operator =(SkAutoDescriptor && that)162 SkAutoDescriptor& SkAutoDescriptor::operator=(SkAutoDescriptor&& that) {
163 if (that.fDesc == (SkDescriptor*)&that.fStorage) {
164 this->reset(*that.getDesc());
165 } else {
166 this->free();
167 fDesc = that.fDesc;
168 that.fDesc = nullptr;
169 }
170 return *this;
171 }
172
~SkAutoDescriptor()173 SkAutoDescriptor::~SkAutoDescriptor() { this->free(); }
174
MakeFromBuffer(SkReadBuffer & buffer)175 std::optional<SkAutoDescriptor> SkAutoDescriptor::MakeFromBuffer(SkReadBuffer& buffer) {
176 SkDescriptor descriptorHeader;
177 if (!buffer.readPad32(&descriptorHeader, sizeof(SkDescriptor))) { return {}; }
178
179 // Basic bounds check on header length to make sure that bodyLength calculation does not
180 // underflow.
181 if (descriptorHeader.getLength() < sizeof(SkDescriptor)) { return {}; }
182 uint32_t bodyLength = descriptorHeader.getLength() - sizeof(SkDescriptor);
183
184 // Make sure the fLength makes sense with respect to the incoming data.
185 if (bodyLength > buffer.available()) {
186 return {};
187 }
188
189 SkAutoDescriptor ad{descriptorHeader.getLength()};
190 memcpy(ad.fDesc, &descriptorHeader, sizeof(SkDescriptor));
191 if (!buffer.readPad32(SkTAddOffset<void>(ad.fDesc, sizeof(SkDescriptor)), bodyLength)) {
192 return {};
193 }
194
195 // If the fuzzer produces data but the checksum does not match, let it continue. This will boost
196 // fuzzing speed. We leave the actual checksum computation in for fuzzing builds to make sure
197 // the ComputeChecksum function is covered.
198 #if defined(SK_BUILD_FOR_FUZZER)
199 SkDescriptor::ComputeChecksum(ad.getDesc());
200 #else
201 if (SkDescriptor::ComputeChecksum(ad.getDesc()) != ad.getDesc()->fChecksum) { return {}; }
202 #endif
203 if (!ad.getDesc()->isValid()) { return {}; }
204
205 return {ad};
206 }
207
reset(size_t size)208 void SkAutoDescriptor::reset(size_t size) {
209 this->free();
210 if (size <= sizeof(fStorage)) {
211 fDesc = new (&fStorage) SkDescriptor{};
212 } else {
213 fDesc = SkDescriptor::Alloc(size).release();
214 }
215 }
216
reset(const SkDescriptor & desc)217 void SkAutoDescriptor::reset(const SkDescriptor& desc) {
218 size_t size = desc.getLength();
219 this->reset(size);
220 memcpy(fDesc, &desc, size);
221 }
222
free()223 void SkAutoDescriptor::free() {
224 if (fDesc == (SkDescriptor*)&fStorage) {
225 fDesc->~SkDescriptor();
226 } else {
227 delete fDesc;
228 }
229 }
230
231
232