ma1 pushed to branch mullvad-browser-140.9.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
-
171b00e6
by Jonathan Kew at 2026-03-23T09:15:13+01:00
-
bd670ab3
by Paul Adenot at 2026-03-23T09:15:19+01:00
5 changed files:
- dom/media/TimeUnits.cpp
- + dom/media/test/crashtests/2014865.html
- dom/media/test/crashtests/crashtests.list
- gfx/thebes/gfxHarfBuzzShaper.cpp
- gfx/thebes/gfxHarfBuzzShaper.h
Changes:
| ... | ... | @@ -80,7 +80,7 @@ TimeUnit TimeUnit::FromSeconds(double aValue, int64_t aBase) { |
| 80 | 80 | // base -- we can keep this for some time until we're confident this is
|
| 81 | 81 | // stable.
|
| 82 | 82 | double inBase = aValue * static_cast<double>(aBase);
|
| 83 | - if (std::abs(inBase) >
|
|
| 83 | + if (std::abs(inBase) >=
|
|
| 84 | 84 | static_cast<double>(std::numeric_limits<int64_t>::max())) {
|
| 85 | 85 | NS_WARNING(
|
| 86 | 86 | nsPrintfCString("Warning: base %" PRId64
|
| 1 | +<!DOCTYPE html>
|
|
| 2 | +<html>
|
|
| 3 | +<head><meta charset="utf-8"></head>
|
|
| 4 | +<body>
|
|
| 5 | +<script>
|
|
| 6 | +/*
|
|
| 7 | + * Trigger TimeUnit::FromSeconds boundary overflow via MSE SourceBuffer.remove()
|
|
| 8 | + *
|
|
| 9 | + * Bug in dom/media/TimeUnits.cpp, FromSeconds():
|
|
| 10 | + * double inBase = aValue * static_cast<double>(aBase);
|
|
| 11 | + * if (std::abs(inBase) > static_cast<double>(INT64_MAX)) return Infinity;
|
|
| 12 | + * return TimeUnit(static_cast<int64_t>(std::round(inBase)), aBase);
|
|
| 13 | + *
|
|
| 14 | + * static_cast<double>(INT64_MAX) rounds UP to 2^63. The check uses strict >,
|
|
| 15 | + * so inBase == 2^63 passes. static_cast<int64_t>(round(2^63)) is UNDEFINED
|
|
| 16 | + * BEHAVIOR (2^63 > INT64_MAX). On x86-64 it produces INT64_MIN (negative infinity),
|
|
| 17 | + * corrupting the TimeUnit. The Interval(start, end) constructor asserts start <= end;
|
|
| 18 | + * with end = -Inf and start = 0, the assertion fires.
|
|
| 19 | + */
|
|
| 20 | + |
|
| 21 | +(async function() {
|
|
| 22 | + if (!window.MediaSource) return;
|
|
| 23 | + |
|
| 24 | + // Find a supported MSE type
|
|
| 25 | + const types = [
|
|
| 26 | + 'audio/webm; codecs="opus"',
|
|
| 27 | + 'video/webm; codecs="vp8"',
|
|
| 28 | + 'video/webm; codecs="vp9"',
|
|
| 29 | + 'audio/mp4; codecs="mp4a.40.2"',
|
|
| 30 | + 'video/mp4; codecs="avc1.42E01E"',
|
|
| 31 | + 'audio/mp4; codecs="flac"',
|
|
| 32 | + ];
|
|
| 33 | + let mimeType = null;
|
|
| 34 | + for (const t of types) {
|
|
| 35 | + if (MediaSource.isTypeSupported(t)) { mimeType = t; break; }
|
|
| 36 | + }
|
|
| 37 | + if (!mimeType) return;
|
|
| 38 | + |
|
| 39 | + // Create MediaSource and SourceBuffer
|
|
| 40 | + const ms = new MediaSource();
|
|
| 41 | + const video = document.createElement('video');
|
|
| 42 | + video.src = URL.createObjectURL(ms);
|
|
| 43 | + document.body.appendChild(video);
|
|
| 44 | + await new Promise(r => ms.addEventListener('sourceopen', r));
|
|
| 45 | + const sb = ms.addSourceBuffer(mimeType);
|
|
| 46 | + |
|
| 47 | + // Critical boundary value: 2^63 / 10^6 ≈ 9223372036854.776
|
|
| 48 | + // This is the value where inBase = value * 10^6 ≈ 2^63 exactly,
|
|
| 49 | + // which passes the > check but causes UB in static_cast<int64_t>
|
|
| 50 | + const criticalValue = 9223372036854.776;
|
|
| 51 | + |
|
| 52 | + // Set duration large enough to allow the remove
|
|
| 53 | + try { ms.duration = criticalValue + 1; } catch(e) {}
|
|
| 54 | + |
|
| 55 | + // Trigger the bug: remove(0, criticalValue) calls
|
|
| 56 | + // TimeUnit::FromSeconds(criticalValue) which overflows
|
|
| 57 | + try {
|
|
| 58 | + sb.remove(0, criticalValue);
|
|
| 59 | + await new Promise(r => {
|
|
| 60 | + sb.addEventListener('updateend', r, { once: true });
|
|
| 61 | + sb.addEventListener('error', r, { once: true });
|
|
| 62 | + setTimeout(r, 500);
|
|
| 63 | + });
|
|
| 64 | + } catch(e) {}
|
|
| 65 | + |
|
| 66 | + // Try a few more boundary values
|
|
| 67 | + const vals = [
|
|
| 68 | + Math.pow(2, 63) / 1e6,
|
|
| 69 | + 9223372036854.775,
|
|
| 70 | + 1e15,
|
|
| 71 | + 1e16,
|
|
| 72 | + Number.MAX_SAFE_INTEGER,
|
|
| 73 | + ];
|
|
| 74 | + for (const val of vals) {
|
|
| 75 | + try {
|
|
| 76 | + if (ms.readyState !== 'open' || sb.updating) break;
|
|
| 77 | + ms.duration = Math.abs(val) + 1;
|
|
| 78 | + sb.remove(0, val);
|
|
| 79 | + await new Promise(r => {
|
|
| 80 | + sb.addEventListener('updateend', r, { once: true });
|
|
| 81 | + sb.addEventListener('error', r, { once: true });
|
|
| 82 | + setTimeout(r, 300);
|
|
| 83 | + });
|
|
| 84 | + } catch(e) {}
|
|
| 85 | + }
|
|
| 86 | + |
|
| 87 | + video.remove();
|
|
| 88 | +})();
|
|
| 89 | +</script>
|
|
| 90 | +</body>
|
|
| 91 | +</html> |
| ... | ... | @@ -188,3 +188,4 @@ load 1905231.webm |
| 188 | 188 | load 1917627.mp4
|
| 189 | 189 | skip-if(Android) load audioworkletprocessor-recursion.html
|
| 190 | 190 | load 2014824.html
|
| 191 | +load 2014865.html |
| ... | ... | @@ -1209,9 +1209,6 @@ static void AddOpenTypeFeature(uint32_t aTag, uint32_t aValue, void* aUserArg) { |
| 1209 | 1209 | * gfxFontShaper override to initialize the text run using HarfBuzz
|
| 1210 | 1210 | */
|
| 1211 | 1211 | |
| 1212 | -static hb_font_funcs_t* sHBFontFuncs = nullptr;
|
|
| 1213 | -static hb_font_funcs_t* sNominalGlyphFunc = nullptr;
|
|
| 1214 | -static hb_unicode_funcs_t* sHBUnicodeFuncs = nullptr;
|
|
| 1215 | 1212 | MOZ_RUNINIT static const hb_script_t sMathScript =
|
| 1216 | 1213 | hb_ot_tag_to_script(HB_TAG('m', 'a', 't', 'h'));
|
| 1217 | 1214 | |
| ... | ... | @@ -1222,52 +1219,58 @@ bool gfxHarfBuzzShaper::Initialize() { |
| 1222 | 1219 | mInitialized = true;
|
| 1223 | 1220 | mCallbackData.mShaper = this;
|
| 1224 | 1221 | |
| 1225 | - if (!sHBFontFuncs) {
|
|
| 1226 | - // static function callback pointers, initialized by the first
|
|
| 1227 | - // harfbuzz shaper used
|
|
| 1228 | - sHBFontFuncs = hb_font_funcs_create();
|
|
| 1229 | - hb_font_funcs_set_nominal_glyph_func(sHBFontFuncs, HBGetNominalGlyph,
|
|
| 1230 | - nullptr, nullptr);
|
|
| 1231 | - hb_font_funcs_set_nominal_glyphs_func(sHBFontFuncs, HBGetNominalGlyphs,
|
|
| 1232 | - nullptr, nullptr);
|
|
| 1233 | - hb_font_funcs_set_variation_glyph_func(sHBFontFuncs, HBGetVariationGlyph,
|
|
| 1234 | - nullptr, nullptr);
|
|
| 1235 | - hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs, HBGetGlyphHAdvance,
|
|
| 1236 | - nullptr, nullptr);
|
|
| 1237 | - hb_font_funcs_set_glyph_h_advances_func(sHBFontFuncs, HBGetGlyphHAdvances,
|
|
| 1238 | - nullptr, nullptr);
|
|
| 1239 | - hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs, HBGetGlyphVAdvance,
|
|
| 1240 | - nullptr, nullptr);
|
|
| 1241 | - hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs, HBGetGlyphVOrigin,
|
|
| 1242 | - nullptr, nullptr);
|
|
| 1243 | - hb_font_funcs_set_glyph_extents_func(sHBFontFuncs, HBGetGlyphExtents,
|
|
| 1244 | - nullptr, nullptr);
|
|
| 1245 | - hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs, HBGetContourPoint,
|
|
| 1222 | + // Function callback pointers; these are local statics to ensure thread-safe
|
|
| 1223 | + // initialization on first use.
|
|
| 1224 | + static hb_font_funcs_t* sHBFontFuncs = [] {
|
|
| 1225 | + auto* funcs = hb_font_funcs_create();
|
|
| 1226 | + hb_font_funcs_set_nominal_glyph_func(funcs, HBGetNominalGlyph, nullptr,
|
|
| 1227 | + nullptr);
|
|
| 1228 | + hb_font_funcs_set_nominal_glyphs_func(funcs, HBGetNominalGlyphs, nullptr,
|
|
| 1229 | + nullptr);
|
|
| 1230 | + hb_font_funcs_set_variation_glyph_func(funcs, HBGetVariationGlyph, nullptr,
|
|
| 1231 | + nullptr);
|
|
| 1232 | + hb_font_funcs_set_glyph_h_advance_func(funcs, HBGetGlyphHAdvance, nullptr,
|
|
| 1233 | + nullptr);
|
|
| 1234 | + hb_font_funcs_set_glyph_h_advances_func(funcs, HBGetGlyphHAdvances, nullptr,
|
|
| 1235 | + nullptr);
|
|
| 1236 | + hb_font_funcs_set_glyph_v_advance_func(funcs, HBGetGlyphVAdvance, nullptr,
|
|
| 1237 | + nullptr);
|
|
| 1238 | + hb_font_funcs_set_glyph_v_origin_func(funcs, HBGetGlyphVOrigin, nullptr,
|
|
| 1239 | + nullptr);
|
|
| 1240 | + hb_font_funcs_set_glyph_extents_func(funcs, HBGetGlyphExtents, nullptr,
|
|
| 1241 | + nullptr);
|
|
| 1242 | + hb_font_funcs_set_glyph_contour_point_func(funcs, HBGetContourPoint,
|
|
| 1246 | 1243 | nullptr, nullptr);
|
| 1247 | - hb_font_funcs_set_glyph_h_kerning_func(sHBFontFuncs, HBGetHKerning, nullptr,
|
|
| 1244 | + hb_font_funcs_set_glyph_h_kerning_func(funcs, HBGetHKerning, nullptr,
|
|
| 1248 | 1245 | nullptr);
|
| 1249 | - hb_font_funcs_make_immutable(sHBFontFuncs);
|
|
| 1250 | - |
|
| 1251 | - sNominalGlyphFunc = hb_font_funcs_create();
|
|
| 1252 | - hb_font_funcs_set_nominal_glyph_func(sNominalGlyphFunc, HBGetNominalGlyph,
|
|
| 1253 | - nullptr, nullptr);
|
|
| 1254 | - hb_font_funcs_make_immutable(sNominalGlyphFunc);
|
|
| 1255 | - |
|
| 1256 | - sHBUnicodeFuncs = hb_unicode_funcs_create(hb_unicode_funcs_get_empty());
|
|
| 1257 | - hb_unicode_funcs_set_mirroring_func(sHBUnicodeFuncs, HBGetMirroring,
|
|
| 1258 | - nullptr, nullptr);
|
|
| 1259 | - hb_unicode_funcs_set_script_func(sHBUnicodeFuncs, HBGetScript, nullptr,
|
|
| 1260 | - nullptr);
|
|
| 1261 | - hb_unicode_funcs_set_general_category_func(
|
|
| 1262 | - sHBUnicodeFuncs, HBGetGeneralCategory, nullptr, nullptr);
|
|
| 1263 | - hb_unicode_funcs_set_combining_class_func(
|
|
| 1264 | - sHBUnicodeFuncs, HBGetCombiningClass, nullptr, nullptr);
|
|
| 1265 | - hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs, HBUnicodeCompose,
|
|
| 1266 | - nullptr, nullptr);
|
|
| 1267 | - hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs, HBUnicodeDecompose,
|
|
| 1268 | - nullptr, nullptr);
|
|
| 1269 | - hb_unicode_funcs_make_immutable(sHBUnicodeFuncs);
|
|
| 1270 | - }
|
|
| 1246 | + hb_font_funcs_make_immutable(funcs);
|
|
| 1247 | + return funcs;
|
|
| 1248 | + }();
|
|
| 1249 | + |
|
| 1250 | + static hb_font_funcs_t* sNominalGlyphFunc = [] {
|
|
| 1251 | + auto* funcs = hb_font_funcs_create();
|
|
| 1252 | + hb_font_funcs_set_nominal_glyph_func(funcs, HBGetNominalGlyph, nullptr,
|
|
| 1253 | + nullptr);
|
|
| 1254 | + hb_font_funcs_make_immutable(funcs);
|
|
| 1255 | + return funcs;
|
|
| 1256 | + }();
|
|
| 1257 | + |
|
| 1258 | + static hb_unicode_funcs_t* sHBUnicodeFuncs = [] {
|
|
| 1259 | + auto* funcs = hb_unicode_funcs_create(hb_unicode_funcs_get_empty());
|
|
| 1260 | + hb_unicode_funcs_set_mirroring_func(funcs, HBGetMirroring, nullptr,
|
|
| 1261 | + nullptr);
|
|
| 1262 | + hb_unicode_funcs_set_script_func(funcs, HBGetScript, nullptr, nullptr);
|
|
| 1263 | + hb_unicode_funcs_set_general_category_func(funcs, HBGetGeneralCategory,
|
|
| 1264 | + nullptr, nullptr);
|
|
| 1265 | + hb_unicode_funcs_set_combining_class_func(funcs, HBGetCombiningClass,
|
|
| 1266 | + nullptr, nullptr);
|
|
| 1267 | + hb_unicode_funcs_set_compose_func(funcs, HBUnicodeCompose, nullptr,
|
|
| 1268 | + nullptr);
|
|
| 1269 | + hb_unicode_funcs_set_decompose_func(funcs, HBUnicodeDecompose, nullptr,
|
|
| 1270 | + nullptr);
|
|
| 1271 | + hb_unicode_funcs_make_immutable(funcs);
|
|
| 1272 | + return funcs;
|
|
| 1273 | + }();
|
|
| 1271 | 1274 | |
| 1272 | 1275 | gfxFontEntry* entry = mFont->GetFontEntry();
|
| 1273 | 1276 | if (!mUseFontGetGlyph) {
|
| ... | ... | @@ -1314,23 +1317,23 @@ bool gfxHarfBuzzShaper::Initialize() { |
| 1314 | 1317 | hb_buffer_set_cluster_level(mBuffer,
|
| 1315 | 1318 | HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
|
| 1316 | 1319 | |
| 1317 | - auto* funcs =
|
|
| 1318 | - mFont->GetFontEntry()->HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' '))
|
|
| 1319 | - ? sNominalGlyphFunc
|
|
| 1320 | - : sHBFontFuncs;
|
|
| 1321 | - mHBFont = CreateHBFont(mFont, funcs, &mCallbackData);
|
|
| 1320 | + bool isCFF =
|
|
| 1321 | + mFont->GetFontEntry()->HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' '));
|
|
| 1322 | + auto* funcs = isCFF ? sNominalGlyphFunc : sHBFontFuncs;
|
|
| 1323 | + mHBFont = CreateHBFont(mFont, funcs, &mCallbackData, isCFF);
|
|
| 1322 | 1324 | |
| 1323 | 1325 | return true;
|
| 1324 | 1326 | }
|
| 1325 | 1327 | |
| 1326 | 1328 | hb_font_t* gfxHarfBuzzShaper::CreateHBFont(gfxFont* aFont,
|
| 1327 | 1329 | hb_font_funcs_t* aFontFuncs,
|
| 1328 | - FontCallbackData* aCallbackData) {
|
|
| 1330 | + FontCallbackData* aCallbackData,
|
|
| 1331 | + bool aCreateSubfont) {
|
|
| 1329 | 1332 | auto face(aFont->GetFontEntry()->GetHBFace());
|
| 1330 | 1333 | hb_font_t* result = hb_font_create(face);
|
| 1331 | 1334 | |
| 1332 | 1335 | if (aFontFuncs && aCallbackData) {
|
| 1333 | - if (aFontFuncs == sNominalGlyphFunc) {
|
|
| 1336 | + if (aCreateSubfont) {
|
|
| 1334 | 1337 | hb_font_t* subfont = hb_font_create_sub_font(result);
|
| 1335 | 1338 | hb_font_destroy(result);
|
| 1336 | 1339 | result = subfont;
|
| ... | ... | @@ -95,7 +95,8 @@ class gfxHarfBuzzShaper : public gfxFontShaper { |
| 95 | 95 | // bounds, etc; if not, the built-in hb_ot font functions will be used.
|
| 96 | 96 | static hb_font_t* CreateHBFont(gfxFont* aFont,
|
| 97 | 97 | hb_font_funcs_t* aFontFuncs = nullptr,
|
| 98 | - FontCallbackData* aCallbackData = nullptr);
|
|
| 98 | + FontCallbackData* aCallbackData = nullptr,
|
|
| 99 | + bool aCreateSubfont = false);
|
|
| 99 | 100 | |
| 100 | 101 | hb_font_t* GetHBFont() const { return mHBFont; }
|
| 101 | 102 | hb_face_t* GetHBFace() const { return hb_font_get_face(mHBFont); }
|