Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkDescriptor.cpp
Go to the documentation of this file.
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
9
14#include "src/core/SkChecksum.h"
17
18#include <cstring>
19
20std::unique_ptr<SkDescriptor> SkDescriptor::Alloc(size_t length) {
22 void* allocation = ::operator new(length);
23 return std::unique_ptr<SkDescriptor>(new (allocation) SkDescriptor{});
24}
25
26void SkDescriptor::operator delete(void* p) { ::operator delete(p); }
27void* SkDescriptor::operator new(size_t) {
28 SK_ABORT("Descriptors are created with placement new.");
29}
30
32 buffer.writePad32(static_cast<const void*>(this), this->fLength);
33}
34
35void* SkDescriptor::addEntry(uint32_t tag, size_t length, const void* data) {
36 SkASSERT(tag);
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
53 fChecksum = SkDescriptor::ComputeChecksum(this);
54}
55
56const 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
72std::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
78bool 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
94 const SkScalerContextRec* rec = static_cast<const SkScalerContextRec*>(
95 this->findEntry(kRec_SkDescriptorTag, nullptr));
96
98 result.appendf(" Checksum: %x\n", fChecksum);
99 if (rec != nullptr) {
100 result.append(rec->dump());
101 }
102 return result;
103}
104
105uint32_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
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
145SkAutoDescriptor::SkAutoDescriptor(size_t size) { this->reset(size); }
148 this->reset(*that.getDesc());
149}
151 this->reset(*that.getDesc());
152 return *this;
153}
155 if (that.fDesc == (SkDescriptor*)&that.fStorage) {
156 this->reset(*that.getDesc());
157 } else {
158 fDesc = that.fDesc;
159 that.fDesc = nullptr;
160 }
161}
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
174
175std::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
208void 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
218 size_t size = desc.getLength();
219 this->reset(size);
220 memcpy(fDesc, &desc, size);
221}
222
223void SkAutoDescriptor::free() {
224 if (fDesc == (SkDescriptor*)&fStorage) {
225 fDesc->~SkDescriptor();
226 } else {
227 delete fDesc;
228 }
229}
230
231
m reset()
int count
static constexpr T SkAlign4(T x)
Definition SkAlign.h:16
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
#define kRec_SkDescriptorTag
constexpr uint32_t SkToU32(S x)
Definition SkTo.h:26
SkAutoDescriptor & operator=(const SkAutoDescriptor &)
SkDescriptor * getDesc() const
static std::optional< SkAutoDescriptor > MakeFromBuffer(SkReadBuffer &buffer)
void reset(size_t size)
void * addEntry(uint32_t tag, size_t length, const void *data=nullptr)
void flatten(SkWriteBuffer &buffer) const
static std::unique_ptr< SkDescriptor > Alloc(size_t length)
std::unique_ptr< SkDescriptor > copy() const
void computeChecksum()
uint32_t getLength() const
SkString dumpRec() const
bool isValid() const
const void * findEntry(uint32_t tag, uint32_t *length) const
bool operator==(const SkDescriptor &other) const
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:550
static const uint8_t buffer[]
GAsyncResult * result
size_t length
uint32_t Hash32(const void *data, size_t bytes, uint32_t seed)
Point offset
SkString dump() const