[core] Allow SkArenaAlloc to query malloc() for usable size

When allocating memory with malloc(), allocators can provide a larger
size than requested. SkArenaAlloc tries to guess what jemalloc would
return, and align its allocation requests on the to-be-provided
size. Some platforms (e.g. glibc or bionic with malloc_usable_size(),
macOS with malloc_size()) can provide the actual value.

This CL adds support to skia's malloc() wrappers to get this data, and
to SkArenaAlloc to use it. Note that as is, this is a no-op in skia
proper. Indeed, clients can (and do, for instance Chromium does)
override sk_malloc() (and friends), so Skia cannot assume that
sk_malloc() memory comes from malloc().

To implement this, a client needs to override sk_malloc_usable_size() to
return the actual value.

Bug: chromium:1335342
Change-Id: Id8ea177e9adccc9c4446fe379b6f05e726ea07ce
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/549516
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Herb Derby <herb@google.com>
This commit is contained in:
Benoît Lizé 2022-07-07 15:57:37 +02:00 committed by SkCQ
parent 955b73beec
commit 916351bd6e
3 changed files with 20 additions and 0 deletions

View File

@ -78,6 +78,10 @@ SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize);
SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize); SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize);
SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize); SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize);
// Returns the true usable size provided by the underlying allocator, or 0 if
// querying the allocation size is not supported.
SK_API extern size_t sk_malloc_usable_size(void* buffer);
/** /**
* These variants return nullptr on failure * These variants return nullptr on failure
*/ */

View File

@ -5,6 +5,7 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "include/private/SkMalloc.h"
#include "src/core/SkArenaAlloc.h" #include "src/core/SkArenaAlloc.h"
#include <algorithm> #include <algorithm>
@ -93,6 +94,13 @@ void SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) {
} }
char* newBlock = static_cast<char*>(sk_malloc_throw(allocationSize, 1)); char* newBlock = static_cast<char*>(sk_malloc_throw(allocationSize, 1));
size_t actualAllocatedSize = sk_malloc_usable_size(newBlock);
// 0 means that the allocated size is not available, don't change anything
// then.
if (actualAllocatedSize) {
AssertRelease(actualAllocatedSize >= allocationSize);
allocationSize = actualAllocatedSize;
}
auto previousDtor = fDtorCursor; auto previousDtor = fDtorCursor;
fCursor = newBlock; fCursor = newBlock;

View File

@ -20,3 +20,11 @@ void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize) {
void* sk_malloc_canfail(size_t count, size_t elemSize) { void* sk_malloc_canfail(size_t count, size_t elemSize) {
return sk_malloc_canfail(SkSafeMath::Mul(count, elemSize)); return sk_malloc_canfail(SkSafeMath::Mul(count, elemSize));
} }
size_t sk_malloc_usable_size(void* buffer) {
// Since sk_malloc() can be overridden by clients, there is no guarantee
// that the memory allocated with it comes from malloc(). So the default
// implementation can only return 0 to signal that generic support is not
// possible.
return 0;
}