Centralize mask byte calculations

These calculations are usually done in place around the code,
but most implementation don't take the care needed for safe calculation.

I have provided safe implementations for use around the code. It
will take a while to track down all the independant implementations
and convert them over.

BUG=skia:7515

Change-Id: Ice6a9be2e8e5ebef18d472adb26c17b03177ef47
Reviewed-on: https://skia-review.googlesource.com/111120
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2018-02-28 14:03:18 -05:00 committed by Skia Commit-Bot
parent be1b397180
commit 8994150a43
2 changed files with 77 additions and 9 deletions

View File

@ -12,24 +12,86 @@
/** returns the product if it is positive and fits in 31 bits. Otherwise this /** returns the product if it is positive and fits in 31 bits. Otherwise this
returns 0. returns 0.
*/ */
static int32_t safeMul32(int32_t a, int32_t b) { static size_t safe_mul(size_t a, size_t b) {
int64_t size = sk_64_mul(a, b); SkSafeMath safe;
if (size > 0 && sk_64_isS32(size)) { size_t r = safe.mul(a, b);
return sk_64_asS32(size); if (safe) {
return r;
} }
return 0; return 0;
} }
static size_t safe_align4(size_t v) {
uint64_t adjusted = v + 3;
uint64_t possible = adjusted > v ? (adjusted & ~3) : 0;
return SkTFitsIn<size_t>(possible) ? possible : 0;
}
size_t SkMask::computeImageSize() const { size_t SkMask::computeImageSize() const {
return safeMul32(fBounds.height(), fRowBytes); auto height = fBounds.height();
auto safeHeight = SkTo<uint32_t>(height >= 0 ? height : 0);
return safe_mul(safeHeight, fRowBytes);
} }
size_t SkMask::computeTotalImageSize() const { size_t SkMask::computeTotalImageSize() const {
size_t size = this->computeImageSize(); return ComputeImageSize(fFormat, fBounds.width(), fBounds.height());
if (fFormat == SkMask::k3D_Format) { }
size = safeMul32(SkToS32(size), 3);
static size_t bits_to_bytes(size_t bits) {
return (bits + 7) >> 3;
}
size_t SkMask::AlignmentForMask(SkMask::Format format) {
switch (format) {
case SkMask::kBW_Format:
return alignof(uint8_t);
case SkMask::kA8_Format:
return alignof(uint8_t);
case SkMask::k3D_Format:
return alignof(uint8_t);
case SkMask::kARGB32_Format:
return alignof(uint32_t);
case SkMask::kLCD16_Format:
return alignof(uint16_t);
default:
SK_ABORT("Unknown mask format.");
break;
} }
return size; // Should not reach here.
return alignof(uint64_t);
}
size_t SkMask::ComputeRowBytes(SkMask::Format format, int32_t width) {
auto safeWidth = SkTo<uint32_t>(width >= 0 ? width : 0);
switch (format) {
case SkMask::kBW_Format:
// Always safe.
return SkTo<size_t>(bits_to_bytes(safeWidth));
case SkMask::kA8_Format:
return safe_align4(static_cast<size_t>(safeWidth));
case SkMask::k3D_Format:
return safe_align4(static_cast<size_t>(safeWidth));
case SkMask::kARGB32_Format:
return safe_mul(safeWidth, sizeof(uint32_t));
case SkMask::kLCD16_Format:
return safe_align4(safe_mul(safeWidth, sizeof(uint16_t)));
default:
SK_ABORT("Unknown mask format.");
break;
}
// Should not reach here.
return 0;
}
size_t SkMask::ComputeImageSize(SkMask::Format format, int32_t width, int32_t height) {
size_t size = ComputeRowBytes(format, width);
if (format == SkMask::k3D_Format) {
size = safe_mul(size, 3);
}
auto safeHeight = SkTo<uint32_t>(height >= 0 ? height : 0);
auto result = safe_mul(size, safeHeight);
return result;
} }
/** We explicitly use this allocator for SkBimap pixels, so that we can /** We explicitly use this allocator for SkBimap pixels, so that we can

View File

@ -118,6 +118,12 @@ struct SkMask {
kUninit_Alloc, kUninit_Alloc,
kZeroInit_Alloc, kZeroInit_Alloc,
}; };
static size_t AlignmentForMask(SkMask::Format format);
// Return 0 if overflow.
static size_t ComputeRowBytes(SkMask::Format format, int32_t width);
// Return 0 if overflow.
static size_t ComputeImageSize(SkMask::Format format, int32_t width, int32_t height);
static uint8_t* AllocImage(size_t bytes, AllocType = kUninit_Alloc); static uint8_t* AllocImage(size_t bytes, AllocType = kUninit_Alloc);
static void FreeImage(void* image); static void FreeImage(void* image);