Always check AutoFTAccess::face() for nullptr.

For various reasons AutoFTAccess::face() can return nullptr,
particularly in the case of fonts backed more or less by nothing, or by
users who keep plowing on using an SkTypeface which claims not to
actually have any glyphs. Clean up all the callers to do something which
makes sense when nullptr is returned.

Bug: oss-fuzz:23862
Change-Id: Ifa8e2abbd6dc0e4f41857240c4eb95709dfe5178
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/301301
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Herb Derby <herb@google.com>
This commit is contained in:
Ben Wagner 2020-07-08 11:58:18 -04:00 committed by Skia Commit-Bot
parent 8c3171f531
commit 6669b01267

View File

@ -102,6 +102,9 @@ static SkScalar SkFT_FixedToScalar(FT_Fixed x) {
return SkFixedToScalar(x);
}
using SkUniqueFTFace =
std::unique_ptr<FT_FaceRec, SkFunctionWrapper<decltype(FT_Done_Face), FT_Done_Face>>;
//////////////////////////////////////////////////////////////////////////
using FT_Alloc_size_t = SkCallableTraits<FT_Alloc_Func>::argument<1>::type;
@ -296,7 +299,7 @@ static void unref_ft_library() {
struct SkFaceRec {
SkFaceRec* fNext;
std::unique_ptr<FT_FaceRec, SkFunctionWrapper<decltype(FT_Done_Face), FT_Done_Face>> fFace;
SkUniqueFTFace fFace;
FT_StreamRec fFTStream;
std::unique_ptr<SkStreamAsset> fSkStream;
uint32_t fRefCnt;
@ -652,10 +655,14 @@ std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_FreeType::onGetAdvancedMet
}
void SkTypeface_FreeType::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
SkASSERT(dstArray);
AutoFTAccess fta(this);
FT_Face face = fta.face();
if (!face) {
return;
}
FT_Long numGlyphs = face->num_glyphs;
if (!dstArray) { SkASSERT(numGlyphs == 0); }
sk_bzero(dstArray, sizeof(SkUnichar) * numGlyphs);
FT_UInt glyphIndex;
@ -671,11 +678,17 @@ void SkTypeface_FreeType::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
}
void SkTypeface_FreeType::getPostScriptGlyphNames(SkString* dstArray) const {
SkASSERT(dstArray);
AutoFTAccess fta(this);
FT_Face face = fta.face();
if (face && FT_HAS_GLYPH_NAMES(face)) {
for (int gID = 0; gID < face->num_glyphs; gID++) {
if (!face) {
return;
}
FT_Long numGlyphs = face->num_glyphs;
if (!dstArray) { SkASSERT(numGlyphs == 0); }
if (FT_HAS_GLYPH_NAMES(face)) {
for (int gID = 0; gID < numGlyphs; ++gID) {
char glyphName[128]; // PS limit for names is 127 bytes.
FT_Get_Glyph_Name(face, gID, glyphName, 128);
dstArray[gID] = glyphName;
@ -709,14 +722,18 @@ SkScalerContext* SkTypeface_FreeType::onCreateScalerContext(const SkScalerContex
std::unique_ptr<SkFontData> SkTypeface_FreeType::cloneFontData(
const SkFontArguments& args) const {
SkString name;
AutoFTAccess fta(this);
FT_Face face = fta.face();
Scanner::AxisDefinitions axisDefinitions;
if (!face) {
return nullptr;
}
Scanner::AxisDefinitions axisDefinitions;
if (!Scanner::GetAxes(face, &axisDefinitions)) {
return nullptr;
}
SkString name;
SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(),
axisValues, name);
@ -768,9 +785,7 @@ void SkTypeface_FreeType::onFilterRec(SkScalerContextRec* rec) const {
}
int SkTypeface_FreeType::GetUnitsPerEm(FT_Face face) {
if (!face) {
return 0;
}
SkASSERT(face);
SkScalar upem = SkIntToScalar(face->units_per_EM);
// At least some versions of FreeType set face->units_per_EM to 0 for bitmap only fonts.
@ -786,6 +801,9 @@ int SkTypeface_FreeType::GetUnitsPerEm(FT_Face face) {
int SkTypeface_FreeType::onGetUPEM() const {
AutoFTAccess fta(this);
FT_Face face = fta.face();
if (!face) {
return 0;
}
return GetUnitsPerEm(face);
}
@ -1722,6 +1740,9 @@ int SkTypeface_FreeType::onGetVariationDesignParameters(
int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const {
AutoFTAccess fta(this);
FT_Face face = fta.face();
if (!face) {
return 0;
}
FT_ULong tableCount = 0;
FT_Error error;
@ -1751,6 +1772,9 @@ size_t SkTypeface_FreeType::onGetTableData(SkFontTableTag tag, size_t offset,
{
AutoFTAccess fta(this);
FT_Face face = fta.face();
if (!face) {
return 0;
}
FT_ULong tableLength = 0;
FT_Error error;
@ -1778,6 +1802,9 @@ size_t SkTypeface_FreeType::onGetTableData(SkFontTableTag tag, size_t offset,
sk_sp<SkData> SkTypeface_FreeType::onCopyTableData(SkFontTableTag tag) const {
AutoFTAccess fta(this);
FT_Face face = fta.face();
if (!face) {
return nullptr;
}
FT_ULong tableLength = 0;
FT_Error error;
@ -1852,14 +1879,12 @@ bool SkTypeface_FreeType::Scanner::recognizedFont(SkStreamAsset* stream, int* nu
SkAutoMutexExclusive libraryLock(fLibraryMutex);
FT_StreamRec streamRec;
FT_Face face = this->openFace(stream, -1, &streamRec);
if (nullptr == face) {
SkUniqueFTFace face(this->openFace(stream, -1, &streamRec));
if (!face) {
return false;
}
*numFaces = face->num_faces;
FT_Done_Face(face);
return true;
}
@ -1871,8 +1896,8 @@ bool SkTypeface_FreeType::Scanner::scanFont(
SkAutoMutexExclusive libraryLock(fLibraryMutex);
FT_StreamRec streamRec;
FT_Face face = this->openFace(stream, ttcIndex, &streamRec);
if (nullptr == face) {
SkUniqueFTFace face(this->openFace(stream, ttcIndex, &streamRec));
if (!face) {
return false;
}
@ -1887,7 +1912,7 @@ bool SkTypeface_FreeType::Scanner::scanFont(
}
PS_FontInfoRec psFontInfo;
TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2));
TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face.get(), ft_sfnt_os2));
if (os2 && os2->version != 0xffff) {
weight = os2->usWeightClass;
width = os2->usWidthClass;
@ -1896,7 +1921,7 @@ bool SkTypeface_FreeType::Scanner::scanFont(
if (SkToBool(os2->fsSelection & (1u << 9))) {
slant = SkFontStyle::kOblique_Slant;
}
} else if (0 == FT_Get_PS_Font_Info(face, &psFontInfo) && psFontInfo.weight) {
} else if (0 == FT_Get_PS_Font_Info(face.get(), &psFontInfo) && psFontInfo.weight) {
static const struct {
char const * const name;
int const weight;
@ -1947,13 +1972,15 @@ bool SkTypeface_FreeType::Scanner::scanFont(
*isFixedPitch = FT_IS_FIXED_WIDTH(face);
}
bool success = GetAxes(face, axes);
FT_Done_Face(face);
return success;
if (axes && !GetAxes(face.get(), axes)) {
return false;
}
return true;
}
bool SkTypeface_FreeType::Scanner::GetAxes(FT_Face face, AxisDefinitions* axes) {
if (axes && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
SkASSERT(face && axes);
if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
FT_MM_Var* variations = nullptr;
FT_Error err = FT_Get_MM_Var(face, &variations);
if (err) {