From 8398175d9cf9f678f065f521839888b4cfcdb2c5 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 21 Mar 2024 16:46:24 -0700 Subject: [PATCH] Add an option to disable use-after-free checks in the backend BUGS=330403836 --- android/filament-android/src/main/cpp/Engine.cpp | 4 +++- .../java/com/google/android/filament/Engine.java | 11 +++++++++-- filament/backend/include/backend/Platform.h | 5 +++++ .../include/private/backend/HandleAllocator.h | 11 ++++++----- filament/backend/src/HandleAllocator.cpp | 12 ++++++++---- filament/backend/src/metal/MetalDriver.mm | 4 +++- filament/backend/src/opengl/OpenGLDriver.cpp | 4 +++- filament/backend/src/vulkan/VulkanDriver.cpp | 2 +- .../backend/src/vulkan/VulkanResourceAllocator.h | 4 ++-- filament/include/filament/Engine.h | 5 +++++ filament/src/details/Engine.cpp | 6 ++++-- 11 files changed, 49 insertions(+), 19 deletions(-) diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp index c9fa78dccd..2677e2f8fa 100644 --- a/android/filament-android/src/main/cpp/Engine.cpp +++ b/android/filament-android/src/main/cpp/Engine.cpp @@ -494,7 +494,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu jlong jobSystemThreadCount, jlong textureUseAfterFreePoolSize, jboolean disableParallelShaderCompile, jint stereoscopicType, jlong stereoscopicEyeCount, - jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge) { + jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge, + jboolean disableHandleUseAfterFreeCheck) { Engine::Builder* builder = (Engine::Builder*) nativeBuilder; Engine::Config config = { .commandBufferSizeMB = (uint32_t) commandBufferSizeMB, @@ -509,6 +510,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu .stereoscopicEyeCount = (uint8_t) stereoscopicEyeCount, .resourceAllocatorCacheSizeMB = (uint32_t) resourceAllocatorCacheSizeMB, .resourceAllocatorCacheMaxAge = (uint8_t) resourceAllocatorCacheMaxAge, + .disableHandleUseAfterFreeCheck = (bool) disableHandleUseAfterFreeCheck, }; builder->config(&config); } diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java index 29aa5fb1c5..97301df980 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java @@ -224,7 +224,8 @@ public class Engine { config.jobSystemThreadCount, config.textureUseAfterFreePoolSize, config.disableParallelShaderCompile, config.stereoscopicType.ordinal(), config.stereoscopicEyeCount, - config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge); + config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge, + config.disableHandleUseAfterFreeCheck); return this; } @@ -422,6 +423,11 @@ public class Engine { * This value determines for how many frames are texture entries kept in the cache. */ public long resourceAllocatorCacheMaxAge = 2; + + /* + * Disable backend handles use-after-free checks. + */ + public boolean disableHandleUseAfterFreeCheck = false; } private Engine(long nativeEngine, Config config) { @@ -1314,7 +1320,8 @@ public class Engine { long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount, long textureUseAfterFreePoolSize, boolean disableParallelShaderCompile, int stereoscopicType, long stereoscopicEyeCount, - long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge); + long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge, + boolean disableHandleUseAfterFreeCheck); private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal); private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext); private static native void nSetBuilderPaused(long nativeBuilder, boolean paused); diff --git a/filament/backend/include/backend/Platform.h b/filament/backend/include/backend/Platform.h index 1d85568a88..f144979544 100644 --- a/filament/backend/include/backend/Platform.h +++ b/filament/backend/include/backend/Platform.h @@ -59,6 +59,11 @@ public: * Currently only honored by the GL and Metal backends. */ bool disableParallelShaderCompile = false; + + /** + * Disable backend handles use-after-free checks. + */ + bool disableHandleUseAfterFreeCheck = false; }; Platform() noexcept; diff --git a/filament/backend/include/private/backend/HandleAllocator.h b/filament/backend/include/private/backend/HandleAllocator.h index 53bab21077..0337b41b0d 100644 --- a/filament/backend/include/private/backend/HandleAllocator.h +++ b/filament/backend/include/private/backend/HandleAllocator.h @@ -49,7 +49,7 @@ namespace filament::backend { template class HandleAllocator { public: - HandleAllocator(const char* name, size_t size) noexcept; + HandleAllocator(const char* name, size_t size, bool disableUseAfterFreeCheck) noexcept; HandleAllocator(HandleAllocator const& rhs) = delete; HandleAllocator& operator=(HandleAllocator const& rhs) = delete; ~HandleAllocator(); @@ -172,7 +172,7 @@ public: uint8_t const age = (tag & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT; auto const pNode = static_cast(p); uint8_t const expectedAge = pNode[-1].age; - ASSERT_POSTCONDITION(expectedAge == age, + ASSERT_POSTCONDITION(!mUseAfterFreeCheckDisabled && expectedAge == age, "use-after-free of Handle with id=%d", handle.getId()); } @@ -187,7 +187,6 @@ public: return handle_cast(const_cast&>(handle)); } - private: template @@ -210,8 +209,9 @@ private: Pool mPool1; Pool mPool2; UTILS_UNUSED_IN_RELEASE const utils::AreaPolicy::HeapArea& mArea; + bool mUseAfterFreeCheckDisabled; public: - explicit Allocator(const utils::AreaPolicy::HeapArea& area); + explicit Allocator(const utils::AreaPolicy::HeapArea& area, bool disableUseAfterFreeCheck); static constexpr size_t getAlignment() noexcept { return MIN_ALIGNMENT; } @@ -237,7 +237,7 @@ private: // check for double-free Node* const pNode = static_cast(p); uint8_t& expectedAge = pNode[-1].age; - ASSERT_POSTCONDITION(expectedAge == age, + ASSERT_POSTCONDITION(!mUseAfterFreeCheckDisabled && expectedAge == age, "double-free of Handle of size %d at %p", size, p); expectedAge = (expectedAge + 1) & 0xF; // fixme @@ -348,6 +348,7 @@ private: mutable utils::Mutex mLock; tsl::robin_map mOverflowMap; HandleBase::HandleId mId = 0; + bool mUseAfterFreeCheckDisabled = false; }; } // namespace filament::backend diff --git a/filament/backend/src/HandleAllocator.cpp b/filament/backend/src/HandleAllocator.cpp index bf8e779614..fb58cb1b58 100644 --- a/filament/backend/src/HandleAllocator.cpp +++ b/filament/backend/src/HandleAllocator.cpp @@ -39,8 +39,10 @@ using namespace utils; template UTILS_NOINLINE -HandleAllocator::Allocator::Allocator(AreaPolicy::HeapArea const& area) - : mArea(area) { +HandleAllocator::Allocator::Allocator(AreaPolicy::HeapArea const& area, + bool disableUseAfterFreeCheck) + : mArea(area), + mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) { // The largest handle this allocator can generate currently depends on the architecture's // min alignment, typically 8 or 16 bytes. @@ -74,8 +76,10 @@ HandleAllocator::Allocator::Allocator(AreaPolicy::HeapArea const& ar // ------------------------------------------------------------------------------------------------ template -HandleAllocator::HandleAllocator(const char* name, size_t size) noexcept - : mHandleArena(name, size) { +HandleAllocator::HandleAllocator(const char* name, size_t size, + bool disableUseAfterFreeCheck) noexcept + : mHandleArena(name, size, disableUseAfterFreeCheck), + mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) { } template diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 518df89f52..1a87b31771 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -98,7 +98,9 @@ Dispatcher MetalDriver::getDispatcher() const noexcept { MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept : mPlatform(*platform), mContext(new MetalContext(driverConfig.textureUseAfterFreePoolSize)), - mHandleAllocator("Handles", driverConfig.handleArenaSize) { + mHandleAllocator("Handles", + driverConfig.handleArenaSize, + driverConfig.disableHandleUseAfterFreeCheck) { mContext->driver = this; mContext->device = mPlatform.createDevice(); diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 23b83ebe17..196d1bd2e6 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -205,7 +205,9 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi : mPlatform(*platform), mContext(mPlatform), mShaderCompilerService(*this), - mHandleAllocator("Handles", driverConfig.handleArenaSize), + mHandleAllocator("Handles", + driverConfig.handleArenaSize, + driverConfig.disableHandleUseAfterFreeCheck), mSamplerMap(32), mDriverConfig(driverConfig) { diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index b140f43369..ce950fbf57 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -209,7 +209,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(), mPlatform->getDevice())), mContext(context), - mResourceAllocator(driverConfig.handleArenaSize), + mResourceAllocator(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck), mResourceManager(&mResourceAllocator), mThreadSafeResourceManager(&mResourceAllocator), mCommands(mPlatform->getDevice(), mPlatform->getGraphicsQueue(), diff --git a/filament/backend/src/vulkan/VulkanResourceAllocator.h b/filament/backend/src/vulkan/VulkanResourceAllocator.h index ac71f0ece0..8563946d48 100644 --- a/filament/backend/src/vulkan/VulkanResourceAllocator.h +++ b/filament/backend/src/vulkan/VulkanResourceAllocator.h @@ -51,8 +51,8 @@ namespace filament::backend { class VulkanResourceAllocator { public: - VulkanResourceAllocator(size_t arenaSize) - : mHandleAllocatorImpl("Handles", arenaSize) + VulkanResourceAllocator(size_t arenaSize, bool disableUseAfterFreeCheck) + : mHandleAllocatorImpl("Handles", arenaSize, disableUseAfterFreeCheck) #if DEBUG_RESOURCE_LEAKS , mDebugOnlyResourceCount(RESOURCE_TYPE_COUNT) { std::memset(mDebugOnlyResourceCount.data(), 0, sizeof(size_t) * RESOURCE_TYPE_COUNT); diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 8c2936ccc3..b741d3abd9 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -335,6 +335,11 @@ public: * This value determines for how many frames are texture entries kept in the cache. */ uint32_t resourceAllocatorCacheMaxAge = 2; + + /* + * Disable backend handles use-after-free checks. + */ + bool disableHandleUseAfterFreeCheck = false; }; diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index c0d3f802fb..dbd49a8b71 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -101,7 +101,8 @@ Engine* FEngine::create(Engine::Builder const& builder) { DriverConfig const driverConfig{ .handleArenaSize = instance->getRequestedDriverHandleArenaSize(), .textureUseAfterFreePoolSize = instance->getConfig().textureUseAfterFreePoolSize, - .disableParallelShaderCompile = instance->getConfig().disableParallelShaderCompile + .disableParallelShaderCompile = instance->getConfig().disableParallelShaderCompile, + .disableHandleUseAfterFreeCheck = instance->getConfig().disableHandleUseAfterFreeCheck }; instance->mDriver = platform->createDriver(sharedContext, driverConfig); @@ -665,7 +666,8 @@ int FEngine::loop() { DriverConfig const driverConfig { .handleArenaSize = getRequestedDriverHandleArenaSize(), .textureUseAfterFreePoolSize = mConfig.textureUseAfterFreePoolSize, - .disableParallelShaderCompile = mConfig.disableParallelShaderCompile + .disableParallelShaderCompile = mConfig.disableParallelShaderCompile, + .disableHandleUseAfterFreeCheck = mConfig.disableHandleUseAfterFreeCheck }; mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig);