diff --git a/filament/backend/include/private/backend/HandleAllocator.h b/filament/backend/include/private/backend/HandleAllocator.h index 38754af3a2..78c4780aa4 100644 --- a/filament/backend/include/private/backend/HandleAllocator.h +++ b/filament/backend/include/private/backend/HandleAllocator.h @@ -222,6 +222,56 @@ public: return static_cast(p); } + template + inline std::enable_if_t< + std::is_pointer_v && std::is_base_of_v>, int16_t> + handle_set_value(Handle& handle, uint8_t v) { + assert_invariant(handle); + auto [p, tag] = handleToPointer(handle.getId()); + + if (isPoolHandle(handle.getId())) { + // check for pool handle use-after-free + if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) { + auto const pNode = static_cast(p); + pNode[-1].test_value = v; + return 1; + } + return 0; + } else { + // check for heap handle use-after-free + if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) { + return -1; + } + return -2; + } + } + + template + inline std::enable_if_t< + std::is_pointer_v && std::is_base_of_v>, int16_t> + handle_get_value(Handle& handle) { + assert_invariant(handle); + auto [p, tag] = handleToPointer(handle.getId()); + + if (isPoolHandle(handle.getId())) { + // check for pool handle use-after-free + if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) { + auto const pNode = static_cast(p); + uint8_t age = pNode[-1].age; + uint8_t test_value = pNode[-1].test_value; + int16_t ret = (int16_t) ((age << 8) | test_value); + return ret; + } + return 0; + } else { + // check for heap handle use-after-free + if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) { + return -1; + } + return -2; + } + } + utils::CString getHandleTag(HandleBase::HandleId key) const noexcept; template @@ -276,7 +326,10 @@ private: class Allocator { friend class HandleAllocator; static constexpr size_t MIN_ALIGNMENT = alignof(std::max_align_t); - struct Node { uint8_t age; }; + struct Node { + uint8_t age; + uint8_t test_value = 0xff; + }; // Note: using the `extra` parameter of PoolAllocator<>, even with a 1-byte structure, // generally increases all pool allocations by 8-bytes because of alignment restrictions. template diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index e045f69dcb..16b2658b75 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -643,6 +643,25 @@ void OpenGLDriver::createVertexBufferInfoR( AttributeArray attributes) { DEBUG_MARKER() construct(vbih, bufferCount, attributeCount, attributes); + + // test ---- + int16_t returned_value = handle_set_value(vbih, 90); + uint8_t age = (uint8_t) (returned_value >> 8); + uint8_t test_value = (returned_value & 0xff); + switch (test_value) { + case -2: + case -1: + case 0: + utils::slog.w << "@@@ createVertexBufferInfoR: unexpected result, age:" << (int) age + << ", test_value:" << (int) test_value << utils::io::endl; + break; + default: + FILAMENT_CHECK_POSTCONDITION(test_value == 1) + << "@@@ createVertexBufferInfoR: shouldn't happen, age:" << (int) age + << ", test_value:" << (int) test_value << utils::io::endl; + break; + } + //---------- } void OpenGLDriver::createVertexBufferR( @@ -761,6 +780,25 @@ void OpenGLDriver::createProgramR(Handle ph, Program&& program) { construct(ph, *this, std::move(program)); CHECK_GL_ERROR(utils::slog.e) + + // test ---- + int16_t returned_value = handle_set_value(ph, 100); + uint8_t age = (uint8_t) (returned_value >> 8); + uint8_t test_value = (returned_value & 0xff); + switch (test_value) { + case -2: + case -1: + case 0: + utils::slog.w << "@@@ createProgramR: unexpected result, age:" << (int)age << ", test_value:" << (int)test_value + << utils::io::endl; + break; + default: + FILAMENT_CHECK_POSTCONDITION(test_value == 1) + << "@@@ createProgramR: shouldn't happen, age:" << (int)age + << ", test_value:" << (int)test_value << utils::io::endl; + break; + } + //---------- } UTILS_NOINLINE @@ -1918,6 +1956,25 @@ void OpenGLDriver::destroyRenderPrimitive(Handle rph) { void OpenGLDriver::destroyProgram(Handle ph) { DEBUG_MARKER() if (ph) { + // test ---- + int16_t returned_value = handle_set_value(ph, 101); + uint8_t age = (uint8_t) (returned_value >> 8); + uint8_t test_value = (returned_value & 0xff); + switch (test_value) { + case -2: + case -1: + case 0: + utils::slog.w << "@@@ destroyProgram: unexpected result, age:" << (int) age + << ", test_value:" << (int) test_value << utils::io::endl; + break; + default: + FILAMENT_CHECK_POSTCONDITION(test_value == 1) + << "@@@ destroyProgram: shouldn't happen, age:" << (int) age + << ", test_value:" << (int) test_value << utils::io::endl; + break; + } + //---------- + OpenGLProgram* p = handle_cast(ph); destruct(ph, p); } @@ -4066,6 +4123,24 @@ void OpenGLDriver::bindPipeline(PipelineState const& state) { setRasterState(state.rasterState); setStencilState(state.stencilState); gl.polygonOffset(state.polygonOffset.slope, state.polygonOffset.constant); + // test ---- + Handle pro = state.program; + int16_t returned_value = handle_get_value(pro); + uint8_t age = (uint8_t)(returned_value >> 8); + uint8_t test_value = (returned_value & 0xff); + switch (test_value) { + case -2: + case -1: + case 0: + utils::slog.w << "@@@ bindPipeline: unexpected result, age:" << (int)age << ", test_value:" << (int)test_value << utils::io::endl; + break; + default: + if (test_value != 100) { + utils::slog.w << "@@@ bindPipeline: program is not valid OpenGLProgram, age:" << (int)age << ", test_value:" << (int)test_value << utils::io::endl; + } + break; + } + //---------- OpenGLProgram* const p = handle_cast(state.program); mValidProgram = useProgram(p); (*mCurrentPushConstants) = p->getPushConstants(); diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index ecc1c89a84..88632f9e56 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -282,6 +282,20 @@ private: return mHandleAllocator.handle_cast(handle); } + template + std::enable_if_t && std::is_base_of_v>, + int16_t> + handle_set_value(Handle& handle, uint8_t v) { + return mHandleAllocator.handle_set_value(handle, v); + } + + template + std::enable_if_t && std::is_base_of_v>, + int16_t> + handle_get_value(Handle& handle) { + return mHandleAllocator.handle_get_value(handle); + } + friend class OpenGLProgram; friend class ShaderCompilerService;