validate text during deserialization
Bug: 796473 Change-Id: I7b6a6c698a5b53c915ef6564852fa51ce7410a3e Reviewed-on: https://skia-review.googlesource.com/88520 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Hal Canary <halcanary@google.com>
This commit is contained in:
parent
8957a1058e
commit
889d521d87
@ -69,7 +69,7 @@ int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding enc
|
||||
count = SkUTF8_CountUnichars((const char*)text, byteLength);
|
||||
break;
|
||||
case kUTF16_SkTextEncoding:
|
||||
count = SkUTF16_CountUnichars((const uint16_t*)text, SkToInt(byteLength >> 1));
|
||||
count = SkUTF16_CountUnichars((const uint16_t*)text, byteLength);
|
||||
break;
|
||||
case kUTF32_SkTextEncoding:
|
||||
count = SkToInt(byteLength >> 2);
|
||||
|
@ -420,9 +420,9 @@ int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyp
|
||||
if (nullptr == glyphs) {
|
||||
switch (this->getTextEncoding()) {
|
||||
case kUTF8_TextEncoding:
|
||||
return SkUTF8_CountUnichars((const char*)textData, byteLength);
|
||||
return SkUTF8_CountUnichars(textData, byteLength);
|
||||
case kUTF16_TextEncoding:
|
||||
return SkUTF16_CountUnichars((const uint16_t*)textData, SkToInt(byteLength >> 1));
|
||||
return SkUTF16_CountUnichars(textData, byteLength);
|
||||
case kUTF32_TextEncoding:
|
||||
return SkToInt(byteLength >> 2);
|
||||
case kGlyphID_TextEncoding:
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "SkImage.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkShaderBase.h"
|
||||
#include "SkUtils.h"
|
||||
#include "SkXfermodePriv.h"
|
||||
|
||||
static bool changes_alpha(const SkPaint& paint) {
|
||||
@ -84,3 +85,21 @@ bool SkPaintPriv::ShouldDither(const SkPaint& p, SkColorType dstCT) {
|
||||
return p.getImageFilter() || p.getMaskFilter()
|
||||
|| !p.getShader() || !as_SB(p.getShader())->isConstant();
|
||||
}
|
||||
|
||||
int SkPaintPriv::ValidCountText(const void* text, size_t length, SkPaint::TextEncoding encoding) {
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
switch (encoding) {
|
||||
case SkPaint::kUTF8_TextEncoding: return SkUTF8_CountUnichars(text, length);
|
||||
case SkPaint::kUTF16_TextEncoding: return SkUTF16_CountUnichars(text, length);
|
||||
case SkPaint::kUTF32_TextEncoding: return SkUTF32_CountUnichars(text, length);
|
||||
case SkPaint::kGlyphID_TextEncoding:
|
||||
if (SkIsAlign2(intptr_t(text)) && SkIsAlign2(length)) {
|
||||
return length >> 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,9 @@ public:
|
||||
}
|
||||
|
||||
static bool ShouldDither(const SkPaint&, SkColorType);
|
||||
|
||||
// returns 0 if buffer is invalid for specified encoding
|
||||
static int ValidCountText(const void* text, size_t length, SkPaint::TextEncoding);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDrawShadowInfo.h"
|
||||
#include "SkPaintPriv.h"
|
||||
#include "SkPatchUtils.h"
|
||||
#include "SkPictureData.h"
|
||||
#include "SkPicturePlayback.h"
|
||||
@ -70,20 +71,28 @@ static const SkRect* get_rect_ptr(SkReadBuffer* reader, SkRect* storage) {
|
||||
|
||||
class TextContainer {
|
||||
public:
|
||||
size_t length() { return fByteLength; }
|
||||
const void* text() { return (const void*)fText; }
|
||||
size_t fByteLength;
|
||||
const char* fText;
|
||||
|
||||
bool validate(SkReadBuffer* reader, int count, const SkPaint& paint) const {
|
||||
return reader->validate(paint.countText(fText, fByteLength) == count);
|
||||
TextContainer(SkReadBuffer* reader, const SkPaint* paint) {
|
||||
if (reader->validate(paint != nullptr)) {
|
||||
fByteLength = reader->readInt();
|
||||
fText = (const char*)reader->skip(fByteLength);
|
||||
if (reader->isValid()) {
|
||||
fCount = SkPaintPriv::ValidCountText(fText, fByteLength, paint->getTextEncoding());
|
||||
reader->validate(fCount >= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void get_text(SkReadBuffer* reader, TextContainer* text) {
|
||||
size_t length = text->fByteLength = reader->readInt();
|
||||
text->fText = (const char*)reader->skip(length);
|
||||
}
|
||||
operator bool() const { return fCount >= 0; }
|
||||
|
||||
size_t length() const { return fByteLength; }
|
||||
const void* text() const { return (const void*)fText; }
|
||||
unsigned count() const { return fCount; }
|
||||
|
||||
private:
|
||||
size_t fByteLength = 0;
|
||||
const char* fText = nullptr;
|
||||
int fCount = -1;
|
||||
};
|
||||
|
||||
void SkPicturePlayback::draw(SkCanvas* canvas,
|
||||
SkPicture::AbortCallback* callback,
|
||||
@ -480,10 +489,9 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_POS_TEXT: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
size_t points = reader->readInt();
|
||||
text.validate(reader, points, *paint);
|
||||
reader->validate(points == text.count());
|
||||
const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint));
|
||||
BREAK_ON_READ_ERROR(reader);
|
||||
|
||||
@ -493,10 +501,9 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_POS_TEXT_TOP_BOTTOM: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
size_t points = reader->readInt();
|
||||
text.validate(reader, points, *paint);
|
||||
reader->validate(points == text.count());
|
||||
const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint));
|
||||
const SkScalar top = reader->readScalar();
|
||||
const SkScalar bottom = reader->readScalar();
|
||||
@ -510,10 +517,9 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_POS_TEXT_H: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
size_t xCount = reader->readInt();
|
||||
text.validate(reader, xCount, *paint);
|
||||
reader->validate(xCount == text.count());
|
||||
const SkScalar constY = reader->readScalar();
|
||||
const SkScalar* xpos = (const SkScalar*)reader->skip(xCount * sizeof(SkScalar));
|
||||
BREAK_ON_READ_ERROR(reader);
|
||||
@ -524,10 +530,9 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_POS_TEXT_H_TOP_BOTTOM: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
size_t xCount = reader->readInt();
|
||||
text.validate(reader, xCount, *paint);
|
||||
reader->validate(xCount == text.count());
|
||||
const SkScalar* xpos = (const SkScalar*)reader->skip((3 + xCount) * sizeof(SkScalar));
|
||||
BREAK_ON_READ_ERROR(reader);
|
||||
|
||||
@ -592,8 +597,7 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_TEXT: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
SkScalar x = reader->readScalar();
|
||||
SkScalar y = reader->readScalar();
|
||||
BREAK_ON_READ_ERROR(reader);
|
||||
@ -615,8 +619,7 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_TEXT_TOP_BOTTOM: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
const SkScalar* ptr = (const SkScalar*)reader->skip(4 * sizeof(SkScalar));
|
||||
BREAK_ON_READ_ERROR(reader);
|
||||
|
||||
@ -633,8 +636,7 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_TEXT_ON_PATH: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
const SkPath& path = fPictureData->getPath(reader);
|
||||
SkMatrix matrix;
|
||||
reader->readMatrix(&matrix);
|
||||
@ -648,8 +650,7 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
int count = reader->readInt();
|
||||
uint32_t flags = reader->read32();
|
||||
TextContainer text;
|
||||
get_text(reader, &text);
|
||||
TextContainer text(reader, paint);
|
||||
const SkRSXform* xform = (const SkRSXform*)reader->skip(count * sizeof(SkRSXform));
|
||||
const SkRect* cull = nullptr;
|
||||
if (flags & DRAW_TEXT_RSXFORM_HAS_CULL) {
|
||||
|
@ -82,8 +82,12 @@ int SkUTF8_CountUnichars(const char utf8[]) {
|
||||
}
|
||||
|
||||
// SAFE: returns -1 if invalid UTF-8
|
||||
int SkUTF8_CountUnicharsWithError(const char utf8[], size_t byteLength) {
|
||||
SkASSERT(utf8 || 0 == byteLength);
|
||||
int SkUTF8_CountUnichars(const void* text, size_t byteLength) {
|
||||
SkASSERT(text);
|
||||
const char* utf8 = static_cast<const char*>(text);
|
||||
if (byteLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
const char* stop = utf8 + byteLength;
|
||||
@ -91,8 +95,8 @@ int SkUTF8_CountUnicharsWithError(const char utf8[], size_t byteLength) {
|
||||
while (utf8 < stop) {
|
||||
int type = utf8_byte_type(*(const uint8_t*)utf8);
|
||||
SkASSERT(type >= -1 && type <= 4);
|
||||
if (!utf8_type_is_valid_leading_byte(type) ||
|
||||
utf8 + type > stop) { // Sequence extends beyond end.
|
||||
if (!utf8_type_is_valid_leading_byte(type) || utf8 + type > stop) {
|
||||
// Sequence extends beyond end.
|
||||
return -1;
|
||||
}
|
||||
while(type-- > 1) {
|
||||
@ -254,16 +258,26 @@ int SkUTF16_CountUnichars(const uint16_t src[]) {
|
||||
return count;
|
||||
}
|
||||
|
||||
int SkUTF16_CountUnichars(const uint16_t src[], int numberOf16BitValues) {
|
||||
SkASSERT(src);
|
||||
// returns -1 on error
|
||||
int SkUTF16_CountUnichars(const void* text, size_t byteLength) {
|
||||
SkASSERT(text);
|
||||
if (byteLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (!SkIsAlign2(intptr_t(text)) || !SkIsAlign2(byteLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint16_t* stop = src + numberOf16BitValues;
|
||||
const uint16_t* src = static_cast<const uint16_t*>(text);
|
||||
const uint16_t* stop = src + (byteLength >> 1);
|
||||
int count = 0;
|
||||
while (src < stop) {
|
||||
unsigned c = *src++;
|
||||
SkASSERT(!SkUTF16_IsLowSurrogate(c));
|
||||
if (SkUTF16_IsHighSurrogate(c)) {
|
||||
SkASSERT(src < stop);
|
||||
if (src >= stop) {
|
||||
return -1;
|
||||
}
|
||||
c = *src++;
|
||||
SkASSERT(SkUTF16_IsLowSurrogate(c));
|
||||
}
|
||||
@ -361,3 +375,24 @@ const char SkHexadecimalDigits::gUpper[16] =
|
||||
const char SkHexadecimalDigits::gLower[16] =
|
||||
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
|
||||
// returns -1 on error
|
||||
int SkUTF32_CountUnichars(const void* text, size_t byteLength) {
|
||||
if (byteLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (!SkIsAlign4(intptr_t(text)) || !SkIsAlign4(byteLength)) {
|
||||
return -1;
|
||||
}
|
||||
const uint32_t kInvalidUnicharMask = 0xFF000000; // unichar fits in 24 bits
|
||||
const uint32_t* ptr = static_cast<const uint32_t*>(text);
|
||||
const uint32_t* stop = ptr + (byteLength >> 2);
|
||||
while (ptr < stop) {
|
||||
if (*ptr & kInvalidUnicharMask) {
|
||||
return -1;
|
||||
}
|
||||
ptr += 1;
|
||||
}
|
||||
return SkToInt(byteLength >> 2);
|
||||
}
|
||||
|
||||
|
@ -43,13 +43,10 @@ inline int SkUTF8_CountUTF8Bytes(const char utf8[]) {
|
||||
|
||||
int SkUTF8_CountUnichars(const char utf8[]);
|
||||
|
||||
/** This function is safe: invalid UTF8 sequences will return -1; */
|
||||
int SkUTF8_CountUnicharsWithError(const char utf8[], size_t byteLength);
|
||||
|
||||
/** This function is safe: invalid UTF8 sequences will return 0; */
|
||||
inline int SkUTF8_CountUnichars(const char utf8[], size_t byteLength) {
|
||||
return SkClampPos(SkUTF8_CountUnicharsWithError(utf8, byteLength));
|
||||
}
|
||||
/** These functions are safe: invalid sequences will return -1; */
|
||||
int SkUTF8_CountUnichars(const void* utf8, size_t byteLength);
|
||||
int SkUTF16_CountUnichars(const void* utf16, size_t byteLength);
|
||||
int SkUTF32_CountUnichars(const void* utf32, size_t byteLength);
|
||||
|
||||
/** This function is safe: invalid UTF8 sequences will return -1
|
||||
* When -1 is returned, ptr is unchanged.
|
||||
@ -83,7 +80,6 @@ size_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[] = nullptr);
|
||||
#define SkUTF16_IsLowSurrogate(c) (((c) & 0xFC00) == 0xDC00)
|
||||
|
||||
int SkUTF16_CountUnichars(const uint16_t utf16[]);
|
||||
int SkUTF16_CountUnichars(const uint16_t utf16[], int numberOf16BitValues);
|
||||
// returns the current unichar and then moves past it (*p++)
|
||||
SkUnichar SkUTF16_NextUnichar(const uint16_t**);
|
||||
// this guy backs up to the previus unichar value, and returns it (*--p)
|
||||
|
@ -2022,9 +2022,9 @@ HRESULT SkXPSDevice::AddGlyphs(IXpsOMObjectFactory* xpsFactory,
|
||||
static int num_glyph_guess(SkPaint::TextEncoding encoding, const void* text, size_t byteLength) {
|
||||
switch (encoding) {
|
||||
case SkPaint::kUTF8_TextEncoding:
|
||||
return SkUTF8_CountUnichars(static_cast<const char *>(text), byteLength);
|
||||
return SkUTF8_CountUnichars(text, byteLength);
|
||||
case SkPaint::kUTF16_TextEncoding:
|
||||
return SkUTF16_CountUnichars(static_cast<const uint16_t *>(text), SkToInt(byteLength));
|
||||
return SkUTF16_CountUnichars(text, byteLength);
|
||||
case SkPaint::kGlyphID_TextEncoding:
|
||||
return SkToInt(byteLength / 2);
|
||||
default:
|
||||
|
@ -174,7 +174,7 @@ static void test_utf16(skiatest::Reporter* reporter) {
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gUni); i++) {
|
||||
size_t count = SkUTF16_FromUnichar(gUni[i], buf);
|
||||
REPORTER_ASSERT(reporter, count == 2);
|
||||
size_t count2 = SkUTF16_CountUnichars(buf, 2);
|
||||
size_t count2 = SkUTF16_CountUnichars(buf, 2 * sizeof(uint16_t));
|
||||
REPORTER_ASSERT(reporter, count2 == 1);
|
||||
const uint16_t* ptr = buf;
|
||||
SkUnichar c = SkUTF16_NextUnichar(&ptr);
|
||||
@ -227,7 +227,7 @@ DEF_TEST(Utils, reporter) {
|
||||
#define LEADING_FOUR_BYTE "\xF0"
|
||||
#define INVALID_BYTE "\xFC"
|
||||
static bool valid_utf8(const char* p, size_t l) {
|
||||
return SkUTF8_CountUnicharsWithError(p, l) >= 0;
|
||||
return SkUTF8_CountUnichars(p, l) >= 0;
|
||||
}
|
||||
DEF_TEST(Utils_UTF8_ValidLength, r) {
|
||||
const char* goodTestcases[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user