Skip to content
Permalink
Browse files
Crash under FontCache::purgeInactiveFontData()
https://bugs.webkit.org/show_bug.cgi?id=156822
<rdar://problem/25373970>

Reviewed by Darin Adler.

In some rare cases, the Font constructor would mutate the FontPlatformData
that is being passed in. This is an issue because because our FontCache
uses the FontPlatformData as key for the cached fonts. This could lead to
crashes because the WTFMove() in FontCache::purgeInactiveFontData() would
nullify values in our HashMap but we would then fail to remove them from
the HashMap (because the key did not match). We would then reference the
null font when looping again when doing font->hasOneRef().

This patch marks Font::m_platformData member as const to avoid such issues
in the future and moves the code altering the FontPlatformData from the
Font constructor into the FontPlatformData constructor. The purpose of
that code was to initialize FontPlatformData::m_cgFont in case the CGFont
passed in the constructor was null.

* platform/graphics/Font.h:
* platform/graphics/FontCache.cpp:
(WebCore::FontCache::fontForPlatformData):
(WebCore::FontCache::purgeInactiveFontData):
* platform/graphics/FontPlatformData.cpp:
(WebCore::FontPlatformData::FontPlatformData):
* platform/graphics/FontPlatformData.h:
* platform/graphics/cocoa/FontCocoa.mm:
(WebCore::webFallbackFontFamily): Deleted.
(WebCore::Font::platformInit): Deleted.
* platform/graphics/cocoa/FontPlatformDataCocoa.mm:
(WebCore::webFallbackFontFamily):
(WebCore::FontPlatformData::setFallbackCGFont):
* platform/graphics/win/FontPlatformDataCGWin.cpp:
(WebCore::FontPlatformData::setFallbackCGFont):


Canonical link: https://commits.webkit.org/175019@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@199890 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
cdumez committed Apr 22, 2016
1 parent bf55df7 commit 55230f4bf2f2551407a025d45aa4e7c345d01fd1
@@ -1,3 +1,41 @@
2016-04-22 Chris Dumez <cdumez@apple.com>

Crash under FontCache::purgeInactiveFontData()
https://bugs.webkit.org/show_bug.cgi?id=156822
<rdar://problem/25373970>

Reviewed by Darin Adler.

In some rare cases, the Font constructor would mutate the FontPlatformData
that is being passed in. This is an issue because because our FontCache
uses the FontPlatformData as key for the cached fonts. This could lead to
crashes because the WTFMove() in FontCache::purgeInactiveFontData() would
nullify values in our HashMap but we would then fail to remove them from
the HashMap (because the key did not match). We would then reference the
null font when looping again when doing font->hasOneRef().

This patch marks Font::m_platformData member as const to avoid such issues
in the future and moves the code altering the FontPlatformData from the
Font constructor into the FontPlatformData constructor. The purpose of
that code was to initialize FontPlatformData::m_cgFont in case the CGFont
passed in the constructor was null.

* platform/graphics/Font.h:
* platform/graphics/FontCache.cpp:
(WebCore::FontCache::fontForPlatformData):
(WebCore::FontCache::purgeInactiveFontData):
* platform/graphics/FontPlatformData.cpp:
(WebCore::FontPlatformData::FontPlatformData):
* platform/graphics/FontPlatformData.h:
* platform/graphics/cocoa/FontCocoa.mm:
(WebCore::webFallbackFontFamily): Deleted.
(WebCore::Font::platformInit): Deleted.
* platform/graphics/cocoa/FontPlatformDataCocoa.mm:
(WebCore::webFallbackFontFamily):
(WebCore::FontPlatformData::setFallbackCGFont):
* platform/graphics/win/FontPlatformDataCGWin.cpp:
(WebCore::FontPlatformData::setFallbackCGFont):

2016-04-22 Chris Dumez <cdumez@apple.com>

Support disabling at runtime IndexedDB constructors exposed to workers
@@ -229,7 +229,7 @@ class Font : public RefCounted<Font> {
float m_maxCharWidth;
float m_avgCharWidth;

FontPlatformData m_platformData;
const FontPlatformData m_platformData;

mutable RefPtr<GlyphPage> m_glyphPageZero;
mutable HashMap<unsigned, RefPtr<GlyphPage>> m_glyphPages;
@@ -396,6 +396,8 @@ Ref<Font> FontCache::fontForPlatformData(const FontPlatformData& platformData)
if (addResult.isNewEntry)
addResult.iterator->value = Font::create(platformData);

ASSERT(addResult.iterator->value->platformData() == platformData);

return *addResult.iterator->value;
}

@@ -435,8 +437,10 @@ void FontCache::purgeInactiveFontData(unsigned purgeCount)
// Fonts may ref other fonts so we loop until there are no changes.
if (fontsToDelete.isEmpty())
break;
for (auto& font : fontsToDelete)
cachedFonts().remove(font->platformData());
for (auto& font : fontsToDelete) {
bool success = cachedFonts().remove(font->platformData());
ASSERT_UNUSED(success, success);
}
};

Vector<FontPlatformDataCacheKey> keysToRemove;
@@ -58,6 +58,8 @@ FontPlatformData::FontPlatformData(CGFontRef cgFont, float size, bool syntheticB
: FontPlatformData(size, syntheticBold, syntheticOblique, orientation, widthVariant, textRenderingMode)
{
m_cgFont = cgFont;
if (!m_cgFont)
setFallbackCGFont();
}
#endif

@@ -216,6 +216,9 @@ class FontPlatformData {
#if PLATFORM(WIN)
void platformDataInit(HFONT, float size, HDC, WCHAR* faceName);
#endif
#if USE(CG)
void setFallbackCGFont();
#endif

public:
bool m_syntheticBold { false };
@@ -79,13 +79,7 @@ static bool fontHasVerticalGlyphs(CTFontRef ctFont)
return false;
}

#if USE(APPKIT)
static NSString *webFallbackFontFamily(void)
{
static NSString *webFallbackFontFamily = [[[NSFont systemFontOfSize:16.0f] familyName] retain];
return webFallbackFontFamily;
}
#else
#if !USE(APPKIT)
bool fontFamilyShouldNotBeUsedForArabic(CFStringRef fontFamilyName)
{
if (!fontFamilyName)
@@ -104,59 +98,6 @@ bool fontFamilyShouldNotBeUsedForArabic(CFStringRef fontFamilyName)
#if USE(APPKIT)
m_syntheticBoldOffset = m_platformData.m_syntheticBold ? 1.0f : 0.f;

bool failedSetup = false;
if (!platformData().cgFont()) {
// Ack! Something very bad happened, like a corrupt font.
// Try looking for an alternate 'base' font for this renderer.

// Special case hack to use "Times New Roman" in place of "Times".
// "Times RO" is a common font whose family name is "Times".
// It overrides the normal "Times" family font.
// It also appears to have a corrupt regular variant.
NSString *fallbackFontFamily;
if ([[m_platformData.nsFont() familyName] isEqual:@"Times"])
fallbackFontFamily = @"Times New Roman";
else
fallbackFontFamily = webFallbackFontFamily();

// Try setting up the alternate font.
// This is a last ditch effort to use a substitute font when something has gone wrong.
#if !ERROR_DISABLED
RetainPtr<NSFont> initialFont = m_platformData.nsFont();
#endif
if (m_platformData.font())
m_platformData.setNSFont([[NSFontManager sharedFontManager] convertFont:m_platformData.nsFont() toFamily:fallbackFontFamily]);
else
m_platformData.setNSFont([NSFont fontWithName:fallbackFontFamily size:m_platformData.size()]);
if (!platformData().cgFont()) {
if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
// OK, couldn't setup Times New Roman as an alternate to Times, fallback
// on the system font. If this fails we have no alternative left.
m_platformData.setNSFont([[NSFontManager sharedFontManager] convertFont:m_platformData.nsFont() toFamily:webFallbackFontFamily()]);
if (!platformData().cgFont()) {
// We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
LOG_ERROR("unable to initialize with font %@", initialFont.get());
failedSetup = true;
}
} else {
// We tried the requested font and the system font. No joy. We have to give up.
LOG_ERROR("unable to initialize with font %@", initialFont.get());
failedSetup = true;
}
}

// Report the problem.
LOG_ERROR("Corrupt font detected, using %@ in place of %@.",
[m_platformData.nsFont() familyName], [initialFont.get() familyName]);
}

// If all else fails, try to set up using the system font.
// This is probably because Times and Times New Roman are both unavailable.
if (failedSetup) {
m_platformData.setNSFont([NSFont systemFontOfSize:[m_platformData.nsFont() pointSize]]);
LOG_ERROR("failed to set up font, using system font %s", m_platformData.font());
}

#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100
// Work around <rdar://problem/19433490>
CGGlyph dummyGlyphs[] = {0, 0};
@@ -58,6 +58,77 @@
{
}

#if USE(APPKIT)

static NSString *webFallbackFontFamily(void)
{
static NSString *webFallbackFontFamily = [[[NSFont systemFontOfSize:16.0f] familyName] retain];
return webFallbackFontFamily;
}

void FontPlatformData::setFallbackCGFont()
{
if (cgFont())
return;

// Ack! Something very bad happened, like a corrupt font.
// Try looking for an alternate 'base' font for this renderer.

// Special case hack to use "Times New Roman" in place of "Times".
// "Times RO" is a common font whose family name is "Times".
// It overrides the normal "Times" family font.
// It also appears to have a corrupt regular variant.
NSString *fallbackFontFamily;
if ([[nsFont() familyName] isEqual:@"Times"])
fallbackFontFamily = @"Times New Roman";
else
fallbackFontFamily = webFallbackFontFamily();

// Try setting up the alternate font.
// This is a last ditch effort to use a substitute font when something has gone wrong.
#if !ERROR_DISABLED
RetainPtr<NSFont> initialFont = nsFont();
#endif
if (font())
setNSFont([[NSFontManager sharedFontManager] convertFont:nsFont() toFamily:fallbackFontFamily]);
else
setNSFont([NSFont fontWithName:fallbackFontFamily size:size()]);

if (cgFont())
return;

if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
// OK, couldn't setup Times New Roman as an alternate to Times, fallback
// on the system font. If this fails we have no alternative left.
setNSFont([[NSFontManager sharedFontManager] convertFont:nsFont() toFamily:webFallbackFontFamily()]);
if (cgFont())
return;

// We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
LOG_ERROR("unable to initialize with font %@", initialFont.get());
} else {
// We tried the requested font and the system font. No joy. We have to give up.
LOG_ERROR("unable to initialize with font %@", initialFont.get());
}

// Report the problem.
LOG_ERROR("Corrupt font detected, using %@ in place of %@.", [nsFont() familyName], [initialFont.get() familyName]);

// If all else fails, try to set up using the system font.
// This is probably because Times and Times New Roman are both unavailable.
ASSERT(!cgFont());
setNSFont([NSFont systemFontOfSize:[nsFont() pointSize]]);
LOG_ERROR("failed to set up font, using system font %s", font());
}

#else

void FontPlatformData::setFallbackCGFont()
{
}

#endif

void FontPlatformData::platformDataInit(const FontPlatformData& f)
{
m_font = f.m_font;
@@ -72,7 +72,7 @@ class FontPlatformData {

HarfBuzzFace* harfBuzzFace() const;

bool isFixedPitch();
bool isFixedPitch() const;
float size() const { return m_size; }
void setSize(float size) { m_size = size; }
bool syntheticBold() const { return m_syntheticBold; }
@@ -273,7 +273,7 @@ HarfBuzzFace* FontPlatformData::harfBuzzFace() const
return m_harfBuzzFace.get();
}

bool FontPlatformData::isFixedPitch()
bool FontPlatformData::isFixedPitch() const
{
return m_fixedWidth;
}
@@ -113,6 +113,8 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR*
LOGFONT logfont;
GetObject(font, sizeof(logfont), &logfont);
m_cgFont = adoptCF(CGFontCreateWithPlatformFont(&logfont));
if (!m_useGDI)
m_isSystemFont = !wcscmp(faceName, L"Lucida Grande");
}

FontPlatformData::FontPlatformData(GDIObject<HFONT> hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI)
@@ -155,4 +157,8 @@ bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const
&& m_useGDI == other.m_useGDI;
}

void FontPlatformData::setFallbackCGFont()
{
}

}
@@ -54,6 +54,9 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR*

m_scaledFont = cairo_scaled_font_create(fontFace, &sizeMatrix, &ctm, fontOptions);
cairo_font_face_destroy(fontFace);

if (!m_useGDI && m_size)
m_isSystemFont = !wcscmp(faceName, L"Lucida Grande");
}

FontPlatformData::FontPlatformData(GDIObject<HFONT> font, cairo_font_face_t* fontFace, float size, bool bold, bool oblique)
@@ -86,7 +86,6 @@ void Font::platformInit()
int faceLength = GetTextFace(dc, 0, 0);
Vector<WCHAR> faceName(faceLength);
GetTextFace(dc, faceLength, faceName.data());
m_platformData.setIsSystemFont(!wcscmp(faceName.data(), L"Lucida Grande"));
SelectObject(dc, oldFont);

fAscent = ascentConsideringMacAscentHack(faceName.data(), fAscent, fDescent);
@@ -46,7 +46,6 @@ void Font::platformInit()
m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_platformData.setIsSystemFont(false);

if (m_platformData.useGDI())
return initGDIFont();
@@ -55,7 +54,6 @@ void Font::platformInit()
m_fontMetrics.reset();
m_avgCharWidth = 0;
m_maxCharWidth = 0;
m_platformData.setIsSystemFont(false);
m_scriptCache = 0;
m_scriptFontProperties = 0;
return;
@@ -87,11 +85,6 @@ void Font::platformInit()
}
float xHeight = ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.

int faceLength = ::GetTextFace(dc, 0, 0);
Vector<WCHAR> faceName(faceLength);
::GetTextFace(dc, faceLength, faceName.data());
m_platformData.setIsSystemFont(!wcscmp(faceName.data(), L"Lucida Grande"));

m_fontMetrics.setAscent(ascent);
m_fontMetrics.setDescent(descent);
m_fontMetrics.setLineGap(lineGap);

0 comments on commit 55230f4

Please sign in to comment.