From 4332dfb9640f28ef7daafe340b061d2586d2fc28 Mon Sep 17 00:00:00 2001 From: Ben Wiederhake Date: Sat, 30 Jan 2021 01:24:41 +0100 Subject: [PATCH] LibGfx: Fix dynamic bitmasks in BMPs I overlooked a corner case where we might call the built-in ctz() on zero. Furthermore, the calculation of the shift was wrong and the results were often unusable. Both issue were caused by a forgotten 36daeee34ff04f64c933e94a9cdffe9080061fb0. This time I made sure to look at bmpsuite_files first, and now they look good. Found by OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28985 --- AK/Platform.h | 9 ++++++++- Userland/Libraries/LibGfx/BMPLoader.cpp | 10 ++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/AK/Platform.h b/AK/Platform.h index d8d610e295..99fb61c8df 100644 --- a/AK/Platform.h +++ b/AK/Platform.h @@ -81,9 +81,16 @@ ALWAYS_INLINE int count_trailing_zeroes_32(unsigned int val) } return 0; #endif +} + +ALWAYS_INLINE int count_trailing_zeroes_32_safe(unsigned int val) +{ + if (val == 0) + return 32; + return count_trailing_zeroes_32(val); +} #ifdef AK_OS_BSD_GENERIC # define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC # define CLOCK_REALTIME_COARSE CLOCK_REALTIME #endif -} diff --git a/Userland/Libraries/LibGfx/BMPLoader.cpp b/Userland/Libraries/LibGfx/BMPLoader.cpp index 7954142800..4ab139eff2 100644 --- a/Userland/Libraries/LibGfx/BMPLoader.cpp +++ b/Userland/Libraries/LibGfx/BMPLoader.cpp @@ -368,8 +368,14 @@ static void populate_dib_mask_info_if_needed(BMPLoadingContext& context) continue; } int trailing_zeros = count_trailing_zeroes_32(mask); - int size = count_trailing_zeroes_32(~(mask >> trailing_zeros)); - mask_shifts.append(trailing_zeros - 8); + // If mask is exactly `0xFFFFFFFF`, then we might try to count the trailing zeros of 0x00000000 here, so we need the safe version: + int size = count_trailing_zeroes_32_safe(~(mask >> trailing_zeros)); + if (size > 8) { + // Drop lowest bits if mask is longer than 8 bits. + trailing_zeros += size - 8; + size = 8; + } + mask_shifts.append(size + trailing_zeros - 8); mask_sizes.append(size); } }