From 69c68d01b2420e77283166ffcc7ddb4b0fbc2505 Mon Sep 17 00:00:00 2001 From: Rafael Cintron Date: Fri, 10 Jan 2020 17:58:28 +0000 Subject: [PATCH] Improve Memory Management of Result class The way in which the Result class is used in Dawn can be fragile with respect to memory management because the caller of AcquireError must know they need to delete the returned pointer or a memory leak will occur. We've had a couple of instances where developers have accidentally left out the delete call and managed to get past code review. This CL changes the Result class so that it assumes the error is allocated on the heap and forces the caller to use unique_ptr when calling AcquireError. Bug:dawn:320 Change-Id: I13ec953b0c37eaafbd6ce93c2f719b4743676acb Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/14960 Reviewed-by: Austin Eng Reviewed-by: Corentin Wallez Commit-Queue: Rafael Cintron --- BUILD.gn | 1 - src/common/Result.h | 125 +++++++------- src/dawn_native/Device.cpp | 3 +- src/dawn_native/Device.h | 2 +- src/dawn_native/EncodingContext.h | 3 +- src/dawn_native/Error.cpp | 35 ---- src/dawn_native/Error.h | 63 +++---- src/dawn_native/ErrorData.cpp | 10 +- src/dawn_native/ErrorData.h | 6 +- src/dawn_native/Instance.cpp | 3 +- src/tests/unittests/ErrorTests.cpp | 38 ++--- src/tests/unittests/ResultTests.cpp | 158 +++++++++--------- .../white_box/VulkanErrorInjectorTests.cpp | 2 +- 13 files changed, 194 insertions(+), 255 deletions(-) delete mode 100644 src/dawn_native/Error.cpp diff --git a/BUILD.gn b/BUILD.gn index 5287bee66d..c7df5827aa 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -204,7 +204,6 @@ source_set("libdawn_native_sources") { "src/dawn_native/DynamicUploader.h", "src/dawn_native/EncodingContext.cpp", "src/dawn_native/EncodingContext.h", - "src/dawn_native/Error.cpp", "src/dawn_native/Error.h", "src/dawn_native/ErrorData.cpp", "src/dawn_native/ErrorData.h", diff --git a/src/common/Result.h b/src/common/Result.h index 3e33052fb3..7dc5e2df9e 100644 --- a/src/common/Result.h +++ b/src/common/Result.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -38,10 +39,10 @@ template class Result; -// The interface of Result shoud look like the following. +// The interface of Result should look like the following. // public: // Result(T&& success); -// Result(E&& error); +// Result(std::unique_ptr error); // // Result(Result&& other); // Result& operator=(Result&& other); @@ -52,18 +53,18 @@ class Result; // bool IsSuccess() const; // // T&& AcquireSuccess(); -// E&& AcquireError(); +// std::unique_ptr AcquireError(); // Specialization of Result for returning errors only via pointers. It is basically a pointer // where nullptr is both Success and Empty. template -class DAWN_NO_DISCARD Result { +class DAWN_NO_DISCARD Result { public: Result(); - Result(E* error); + Result(std::unique_ptr error); - Result(Result&& other); - Result& operator=(Result&& other); + Result(Result&& other); + Result& operator=(Result&& other); ~Result(); @@ -71,10 +72,10 @@ class DAWN_NO_DISCARD Result { bool IsSuccess() const; void AcquireSuccess(); - E* AcquireError(); + std::unique_ptr AcquireError(); private: - E* mError = nullptr; + std::unique_ptr mError; }; // Uses SFINAE to try to get alignof(T) but fallback to Default if T isn't defined. @@ -108,7 +109,7 @@ namespace detail { } // namespace detail template -class DAWN_NO_DISCARD Result { +class DAWN_NO_DISCARD Result { public: static_assert(alignof_if_defined_else_default >= 4, "Result reserves two bits for tagging pointers"); @@ -116,13 +117,13 @@ class DAWN_NO_DISCARD Result { "Result reserves two bits for tagging pointers"); Result(T* success); - Result(E* error); + Result(std::unique_ptr error); // Support returning a Result from a Result template - Result(Result&& other); + Result(Result&& other); template - Result& operator=(Result&& other); + Result& operator=(Result&& other); ~Result(); @@ -130,7 +131,7 @@ class DAWN_NO_DISCARD Result { bool IsSuccess() const; T* AcquireSuccess(); - E* AcquireError(); + std::unique_ptr AcquireError(); private: template @@ -140,7 +141,7 @@ class DAWN_NO_DISCARD Result { }; template -class DAWN_NO_DISCARD Result { +class DAWN_NO_DISCARD Result { public: static_assert(alignof_if_defined_else_default >= 4, "Result reserves two bits for tagging pointers"); @@ -148,10 +149,10 @@ class DAWN_NO_DISCARD Result { "Result reserves two bits for tagging pointers"); Result(const T* success); - Result(E* error); + Result(std::unique_ptr error); - Result(Result&& other); - Result& operator=(Result&& other); + Result(Result&& other); + Result& operator=(Result&& other); ~Result(); @@ -159,7 +160,7 @@ class DAWN_NO_DISCARD Result { bool IsSuccess() const; const T* AcquireSuccess(); - E* AcquireError(); + std::unique_ptr AcquireError(); private: intptr_t mPayload = detail::kEmptyPayload; @@ -172,7 +173,7 @@ template class DAWN_NO_DISCARD Result { public: Result(T&& success); - Result(E&& error); + Result(std::unique_ptr error); Result(Result&& other); Result& operator=(Result&& other); @@ -183,7 +184,7 @@ class DAWN_NO_DISCARD Result { bool IsSuccess() const; T&& AcquireSuccess(); - E&& AcquireError(); + std::unique_ptr AcquireError(); private: enum PayloadType { @@ -193,56 +194,52 @@ class DAWN_NO_DISCARD Result { }; PayloadType mType; - E mError; + std::unique_ptr mError; T mSuccess; }; -// Implementation of Result +// Implementation of Result template -Result::Result() { +Result::Result() { } template -Result::Result(E* error) : mError(error) { +Result::Result(std::unique_ptr error) : mError(std::move(error)) { } template -Result::Result(Result&& other) : mError(other.mError) { - other.mError = nullptr; +Result::Result(Result&& other) : mError(std::move(other.mError)) { } template -Result& Result::operator=(Result&& other) { +Result& Result::operator=(Result&& other) { ASSERT(mError == nullptr); - mError = other.mError; - other.mError = nullptr; + mError = std::move(other.mError); return *this; } template -Result::~Result() { +Result::~Result() { ASSERT(mError == nullptr); } template -bool Result::IsError() const { +bool Result::IsError() const { return mError != nullptr; } template -bool Result::IsSuccess() const { +bool Result::IsSuccess() const { return mError == nullptr; } template -void Result::AcquireSuccess() { +void Result::AcquireSuccess() { } template -E* Result::AcquireError() { - E* error = mError; - mError = nullptr; - return error; +std::unique_ptr Result::AcquireError() { + return std::move(mError); } // Implementation details of the tagged pointer Results @@ -262,25 +259,26 @@ namespace detail { } // namespace detail -// Implementation of Result +// Implementation of Result template -Result::Result(T* success) : mPayload(detail::MakePayload(success, detail::Success)) { +Result::Result(T* success) : mPayload(detail::MakePayload(success, detail::Success)) { } template -Result::Result(E* error) : mPayload(detail::MakePayload(error, detail::Error)) { +Result::Result(std::unique_ptr error) + : mPayload(detail::MakePayload(error.release(), detail::Error)) { } template template -Result::Result(Result&& other) : mPayload(other.mPayload) { +Result::Result(Result&& other) : mPayload(other.mPayload) { other.mPayload = detail::kEmptyPayload; static_assert(std::is_same::value || std::is_base_of::value, ""); } template template -Result& Result::operator=(Result&& other) { +Result& Result::operator=(Result&& other) { ASSERT(mPayload == detail::kEmptyPayload); static_assert(std::is_same::value || std::is_base_of::value, ""); mPayload = other.mPayload; @@ -289,51 +287,52 @@ Result& Result::operator=(Result&& other) { } template -Result::~Result() { +Result::~Result() { ASSERT(mPayload == detail::kEmptyPayload); } template -bool Result::IsError() const { +bool Result::IsError() const { return detail::GetPayloadType(mPayload) == detail::Error; } template -bool Result::IsSuccess() const { +bool Result::IsSuccess() const { return detail::GetPayloadType(mPayload) == detail::Success; } template -T* Result::AcquireSuccess() { +T* Result::AcquireSuccess() { T* success = detail::GetSuccessFromPayload(mPayload); mPayload = detail::kEmptyPayload; return success; } template -E* Result::AcquireError() { - E* error = detail::GetErrorFromPayload(mPayload); +std::unique_ptr Result::AcquireError() { + std::unique_ptr error(detail::GetErrorFromPayload(mPayload)); mPayload = detail::kEmptyPayload; - return error; + return std::move(error); } // Implementation of Result template -Result::Result(const T* success) +Result::Result(const T* success) : mPayload(detail::MakePayload(success, detail::Success)) { } template -Result::Result(E* error) : mPayload(detail::MakePayload(error, detail::Error)) { +Result::Result(std::unique_ptr error) + : mPayload(detail::MakePayload(error.release(), detail::Error)) { } template -Result::Result(Result&& other) : mPayload(other.mPayload) { +Result::Result(Result&& other) : mPayload(other.mPayload) { other.mPayload = detail::kEmptyPayload; } template -Result& Result::operator=(Result&& other) { +Result& Result::operator=(Result&& other) { ASSERT(mPayload == detail::kEmptyPayload); mPayload = other.mPayload; other.mPayload = detail::kEmptyPayload; @@ -341,32 +340,32 @@ Result& Result::operator=(Result&& othe } template -Result::~Result() { +Result::~Result() { ASSERT(mPayload == detail::kEmptyPayload); } template -bool Result::IsError() const { +bool Result::IsError() const { return detail::GetPayloadType(mPayload) == detail::Error; } template -bool Result::IsSuccess() const { +bool Result::IsSuccess() const { return detail::GetPayloadType(mPayload) == detail::Success; } template -const T* Result::AcquireSuccess() { +const T* Result::AcquireSuccess() { T* success = detail::GetSuccessFromPayload(mPayload); mPayload = detail::kEmptyPayload; return success; } template -E* Result::AcquireError() { - E* error = detail::GetErrorFromPayload(mPayload); +std::unique_ptr Result::AcquireError() { + std::unique_ptr error(detail::GetErrorFromPayload(mPayload)); mPayload = detail::kEmptyPayload; - return error; + return std::move(error); } // Implementation of Result @@ -375,7 +374,7 @@ Result::Result(T&& success) : mType(Success), mSuccess(std::move(success)) } template -Result::Result(E&& error) : mType(Error), mError(std::move(error)) { +Result::Result(std::unique_ptr error) : mType(Error), mError(std::move(error)) { } template @@ -415,7 +414,7 @@ T&& Result::AcquireSuccess() { } template -E&& Result::AcquireError() { +std::unique_ptr Result::AcquireError() { ASSERT(mType == Error); mType = Acquired; return std::move(mError); diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp index 3926a89286..f5609dc9c7 100644 --- a/src/dawn_native/Device.cpp +++ b/src/dawn_native/Device.cpp @@ -118,10 +118,9 @@ namespace dawn_native { HandleError(type, message); } - void DeviceBase::ConsumeError(ErrorData* error) { + void DeviceBase::ConsumeError(std::unique_ptr error) { ASSERT(error != nullptr); HandleError(error->GetType(), error->GetMessage().c_str()); - delete error; } void DeviceBase::SetUncapturedErrorCallback(wgpu::ErrorCallback callback, void* userdata) { diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h index aa6471fbc5..9d0947d2b7 100644 --- a/src/dawn_native/Device.h +++ b/src/dawn_native/Device.h @@ -251,7 +251,7 @@ namespace dawn_native { void SetDefaultToggles(); - void ConsumeError(ErrorData* error); + void ConsumeError(std::unique_ptr error); // Destroy is used to clean up and release resources used by device, does not wait for GPU // or check errors. diff --git a/src/dawn_native/EncodingContext.h b/src/dawn_native/EncodingContext.h index c16d544c0f..1eef6c5b26 100644 --- a/src/dawn_native/EncodingContext.h +++ b/src/dawn_native/EncodingContext.h @@ -41,9 +41,8 @@ namespace dawn_native { // Functions to handle encoder errors void HandleError(wgpu::ErrorType type, const char* message); - inline void ConsumeError(ErrorData* error) { + inline void ConsumeError(std::unique_ptr error) { HandleError(error->GetType(), error->GetMessage().c_str()); - delete error; } inline bool ConsumedError(MaybeError maybeError) { diff --git a/src/dawn_native/Error.cpp b/src/dawn_native/Error.cpp deleted file mode 100644 index 195afb2e02..0000000000 --- a/src/dawn_native/Error.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 The Dawn Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "dawn_native/Error.h" - -#include "dawn_native/ErrorData.h" - -namespace dawn_native { - - ErrorData* MakeError(InternalErrorType type, - std::string message, - const char* file, - const char* function, - int line) { - ErrorData* error = new ErrorData(type, message); - error->AppendBacktrace(file, function, line); - return error; - } - - void AppendBacktrace(ErrorData* error, const char* file, const char* function, int line) { - error->AppendBacktrace(file, function, line); - } - -} // namespace dawn_native diff --git a/src/dawn_native/Error.h b/src/dawn_native/Error.h index b4b968ae13..7f9dbcbc1e 100644 --- a/src/dawn_native/Error.h +++ b/src/dawn_native/Error.h @@ -16,23 +16,20 @@ #define DAWNNATIVE_ERROR_H_ #include "common/Result.h" +#include "dawn_native/ErrorData.h" #include namespace dawn_native { - // This is the content of an error value for MaybeError or ResultOrError, split off to its own - // file to avoid having all files including headers like and - class ErrorData; - enum class InternalErrorType : uint32_t { Validation, DeviceLost, Unimplemented, OutOfMemory }; // MaybeError and ResultOrError are meant to be used as return value for function that are not // expected to, but might fail. The handling of error is potentially much slower than successes. - using MaybeError = Result; + using MaybeError = Result; template - using ResultOrError = Result; + using ResultOrError = Result; // Returning a success is done like so: // return {}; // for Error @@ -44,7 +41,7 @@ namespace dawn_native { // but shorthand version for specific error types are preferred: // return DAWN_VALIDATION_ERROR("My error message"); #define DAWN_MAKE_ERROR(TYPE, MESSAGE) \ - ::dawn_native::MakeError(TYPE, MESSAGE, __FILE__, __func__, __LINE__) + ::dawn_native::ErrorData::Create(TYPE, MESSAGE, __FILE__, __func__, __LINE__) #define DAWN_VALIDATION_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Validation, MESSAGE) #define DAWN_DEVICE_LOST_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::DeviceLost, MESSAGE) #define DAWN_UNIMPLEMENTED_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Unimplemented, MESSAGE) @@ -57,43 +54,33 @@ namespace dawn_native { // When Errors aren't handled explicitly, calls to functions returning errors should be // wrapped in an DAWN_TRY. It will return the error if any, otherwise keep executing // the current function. -#define DAWN_TRY(EXPR) \ - { \ - auto DAWN_LOCAL_VAR = EXPR; \ - if (DAWN_UNLIKELY(DAWN_LOCAL_VAR.IsError())) { \ - ::dawn_native::ErrorData* error = DAWN_LOCAL_VAR.AcquireError(); \ - ::dawn_native::AppendBacktrace(error, __FILE__, __func__, __LINE__); \ - return {std::move(error)}; \ - } \ - } \ - for (;;) \ +#define DAWN_TRY(EXPR) \ + { \ + auto DAWN_LOCAL_VAR = EXPR; \ + if (DAWN_UNLIKELY(DAWN_LOCAL_VAR.IsError())) { \ + std::unique_ptr<::dawn_native::ErrorData> error = DAWN_LOCAL_VAR.AcquireError(); \ + error->AppendBacktrace(__FILE__, __func__, __LINE__); \ + return {std::move(error)}; \ + } \ + } \ + for (;;) \ break // DAWN_TRY_ASSIGN is the same as DAWN_TRY for ResultOrError and assigns the success value, if // any, to VAR. -#define DAWN_TRY_ASSIGN(VAR, EXPR) \ - { \ - auto DAWN_LOCAL_VAR = EXPR; \ - if (DAWN_UNLIKELY(DAWN_LOCAL_VAR.IsError())) { \ - ErrorData* error = DAWN_LOCAL_VAR.AcquireError(); \ - ::dawn_native::AppendBacktrace(error, __FILE__, __func__, __LINE__); \ - return {std::move(error)}; \ - } \ - VAR = DAWN_LOCAL_VAR.AcquireSuccess(); \ - } \ - for (;;) \ +#define DAWN_TRY_ASSIGN(VAR, EXPR) \ + { \ + auto DAWN_LOCAL_VAR = EXPR; \ + if (DAWN_UNLIKELY(DAWN_LOCAL_VAR.IsError())) { \ + std::unique_ptr error = DAWN_LOCAL_VAR.AcquireError(); \ + error->AppendBacktrace(__FILE__, __func__, __LINE__); \ + return {std::move(error)}; \ + } \ + VAR = DAWN_LOCAL_VAR.AcquireSuccess(); \ + } \ + for (;;) \ break - // Implementation detail of DAWN_TRY and DAWN_TRY_ASSIGN's adding to the Error's backtrace. - void AppendBacktrace(ErrorData* error, const char* file, const char* function, int line); - - // Implementation detail of DAWN_MAKE_ERROR - ErrorData* MakeError(InternalErrorType type, - std::string message, - const char* file, - const char* function, - int line); - } // namespace dawn_native #endif // DAWNNATIVE_ERROR_H_ diff --git a/src/dawn_native/ErrorData.cpp b/src/dawn_native/ErrorData.cpp index 2cd01da277..bdfed7fdaa 100644 --- a/src/dawn_native/ErrorData.cpp +++ b/src/dawn_native/ErrorData.cpp @@ -19,7 +19,15 @@ namespace dawn_native { - ErrorData::ErrorData() = default; + std::unique_ptr ErrorData::Create(InternalErrorType type, + std::string message, + const char* file, + const char* function, + int line) { + std::unique_ptr error = std::make_unique(type, message); + error->AppendBacktrace(file, function, line); + return error; + } ErrorData::ErrorData(InternalErrorType type, std::string message) : mType(type), mMessage(std::move(message)) { diff --git a/src/dawn_native/ErrorData.h b/src/dawn_native/ErrorData.h index a73d90dd23..27004de2f0 100644 --- a/src/dawn_native/ErrorData.h +++ b/src/dawn_native/ErrorData.h @@ -33,7 +33,11 @@ namespace dawn_native { class ErrorData { public: - ErrorData(); + static std::unique_ptr Create(InternalErrorType type, + std::string message, + const char* file, + const char* function, + int line); ErrorData(InternalErrorType type, std::string message); struct BacktraceRecord { diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp index 7219ab6a7b..735c61717f 100644 --- a/src/dawn_native/Instance.cpp +++ b/src/dawn_native/Instance.cpp @@ -177,11 +177,10 @@ namespace dawn_native { bool InstanceBase::ConsumedError(MaybeError maybeError) { if (maybeError.IsError()) { - ErrorData* error = maybeError.AcquireError(); + std::unique_ptr error = maybeError.AcquireError(); ASSERT(error != nullptr); dawn::InfoLog() << error->GetMessage(); - delete error; return true; } diff --git a/src/tests/unittests/ErrorTests.cpp b/src/tests/unittests/ErrorTests.cpp index f7d5bc82ea..514c740865 100644 --- a/src/tests/unittests/ErrorTests.cpp +++ b/src/tests/unittests/ErrorTests.cpp @@ -43,9 +43,8 @@ TEST(ErrorTests, Error_Error) { MaybeError result = ReturnError(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } // Check returning a success ResultOrError with an implicit conversion @@ -68,9 +67,8 @@ TEST(ErrorTests, ResultOrError_Error) { ResultOrError result = ReturnError(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } // Check DAWN_TRY handles successes correctly. @@ -109,9 +107,8 @@ TEST(ErrorTests, TRY_Error) { MaybeError result = Try(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } // Check DAWN_TRY adds to the backtrace. @@ -136,13 +133,10 @@ TEST(ErrorTests, TRY_AddsToBacktrace) { MaybeError doubleResult = DoubleTry(); ASSERT_TRUE(doubleResult.IsError()); - ErrorData* singleData = singleResult.AcquireError(); - ErrorData* doubleData = doubleResult.AcquireError(); + std::unique_ptr singleData = singleResult.AcquireError(); + std::unique_ptr doubleData = doubleResult.AcquireError(); ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size()); - - delete singleData; - delete doubleData; } // Check DAWN_TRY_ASSIGN handles successes correctly. @@ -188,9 +182,8 @@ TEST(ErrorTests, TRY_RESULT_Error) { ResultOrError result = Try(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } // Check DAWN_TRY_ASSIGN adds to the backtrace. @@ -215,13 +208,10 @@ TEST(ErrorTests, TRY_RESULT_AddsToBacktrace) { ResultOrError doubleResult = DoubleTry(); ASSERT_TRUE(doubleResult.IsError()); - ErrorData* singleData = singleResult.AcquireError(); - ErrorData* doubleData = doubleResult.AcquireError(); + std::unique_ptr singleData = singleResult.AcquireError(); + std::unique_ptr doubleData = doubleResult.AcquireError(); ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size()); - - delete singleData; - delete doubleData; } // Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error @@ -241,9 +231,8 @@ TEST(ErrorTests, TRY_RESULT_ConversionToError) { MaybeError result = Try(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } // Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error @@ -264,9 +253,8 @@ TEST(ErrorTests, TRY_RESULT_ConversionToErrorNonPointer) { MaybeError result = Try(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } // Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError @@ -284,9 +272,8 @@ TEST(ErrorTests, TRY_ConversionToErrorOrResult) { ResultOrError result = Try(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } // Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError @@ -304,9 +291,8 @@ TEST(ErrorTests, TRY_ConversionToErrorOrResultNonPointer) { ResultOrError result = Try(); ASSERT_TRUE(result.IsError()); - ErrorData* errorData = result.AcquireError(); + std::unique_ptr errorData = result.AcquireError(); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); - delete errorData; } } // anonymous namespace diff --git a/src/tests/unittests/ResultTests.cpp b/src/tests/unittests/ResultTests.cpp index d991462b13..dd87e22a93 100644 --- a/src/tests/unittests/ResultTests.cpp +++ b/src/tests/unittests/ResultTests.cpp @@ -23,8 +23,8 @@ void TestError(Result* result, E expectedError) { ASSERT_TRUE(result->IsError()); ASSERT_FALSE(result->IsSuccess()); - E storedError = result->AcquireError(); - ASSERT_EQ(storedError, expectedError); + std::unique_ptr storedError = result->AcquireError(); + ASSERT_EQ(*storedError, expectedError); } template @@ -42,94 +42,88 @@ static const float dummyConstSuccess = 42.0f; // Result -// Test constructing an error Result +// Test constructing an error Result TEST(ResultOnlyPointerError, ConstructingError) { - Result result(&dummyError); - TestError(&result, &dummyError); + Result result(std::make_unique(dummyError)); + TestError(&result, dummyError); } -// Test moving an error Result +// Test moving an error Result TEST(ResultOnlyPointerError, MovingError) { - Result result(&dummyError); - Result movedResult(std::move(result)); - TestError(&movedResult, &dummyError); + Result result(std::make_unique(dummyError)); + Result movedResult(std::move(result)); + TestError(&movedResult, dummyError); } -// Test returning an error Result +// Test returning an error Result TEST(ResultOnlyPointerError, ReturningError) { - auto CreateError = []() -> Result { - return {&dummyError}; - }; + auto CreateError = []() -> Result { return {std::make_unique(dummyError)}; }; - Result result = CreateError(); - TestError(&result, &dummyError); + Result result = CreateError(); + TestError(&result, dummyError); } -// Test constructing a success Result +// Test constructing a success Result TEST(ResultOnlyPointerError, ConstructingSuccess) { - Result result; + Result result; ASSERT_TRUE(result.IsSuccess()); ASSERT_FALSE(result.IsError()); } -// Test moving a success Result +// Test moving a success Result TEST(ResultOnlyPointerError, MovingSuccess) { - Result result; - Result movedResult(std::move(result)); + Result result; + Result movedResult(std::move(result)); ASSERT_TRUE(movedResult.IsSuccess()); ASSERT_FALSE(movedResult.IsError()); } -// Test returning a success Result +// Test returning a success Result TEST(ResultOnlyPointerError, ReturningSuccess) { - auto CreateError = []() -> Result { - return {}; - }; + auto CreateError = []() -> Result { return {}; }; - Result result = CreateError(); + Result result = CreateError(); ASSERT_TRUE(result.IsSuccess()); ASSERT_FALSE(result.IsError()); } // Result -// Test constructing an error Result +// Test constructing an error Result TEST(ResultBothPointer, ConstructingError) { - Result result(&dummyError); - TestError(&result, &dummyError); + Result result(std::make_unique(dummyError)); + TestError(&result, dummyError); } -// Test moving an error Result +// Test moving an error Result TEST(ResultBothPointer, MovingError) { - Result result(&dummyError); - Result movedResult(std::move(result)); - TestError(&movedResult, &dummyError); + Result result(std::make_unique(dummyError)); + Result movedResult(std::move(result)); + TestError(&movedResult, dummyError); } -// Test returning an error Result +// Test returning an error Result TEST(ResultBothPointer, ReturningError) { - auto CreateError = []() -> Result { - return {&dummyError}; - }; + auto CreateError = []() -> Result { return {std::make_unique(dummyError)}; }; - Result result = CreateError(); - TestError(&result, &dummyError); + Result result = CreateError(); + TestError(&result, dummyError); } -// Test constructing a success Result +// Test constructing a success Result TEST(ResultBothPointer, ConstructingSuccess) { - Result result(&dummySuccess); + Result result(&dummySuccess); TestSuccess(&result, &dummySuccess); } -// Test moving a success Result +// Test moving a success Result TEST(ResultBothPointer, MovingSuccess) { - Result result(&dummySuccess); - Result movedResult(std::move(result)); + Result result(&dummySuccess); + Result movedResult(std::move(result)); TestSuccess(&movedResult, &dummySuccess); } -// Test returning a success Result +// Test returning a success Result TEST(ResultBothPointer, ReturningSuccess) { auto CreateSuccess = []() -> Result { return {&dummySuccess}; @@ -139,7 +133,7 @@ TEST(ResultBothPointer, ReturningSuccess) { TestSuccess(&result, &dummySuccess); } -// Tests converting from a Result +// Tests converting from a Result TEST(ResultBothPointer, ConversionFromChildClass) { struct T { int a; @@ -149,62 +143,64 @@ TEST(ResultBothPointer, ConversionFromChildClass) { TChild child; T* childAsT = &child; { - Result result(&child); + Result result(&child); TestSuccess(&result, childAsT); } { - Result resultChild(&child); - Result result(std::move(resultChild)); + Result resultChild(&child); + Result result(std::move(resultChild)); TestSuccess(&result, childAsT); } { - Result resultChild(&child); - Result result = std::move(resultChild); + Result resultChild(&child); + Result result = std::move(resultChild); TestSuccess(&result, childAsT); } } -// Result +// Result -// Test constructing an error Result +// Test constructing an error Result TEST(ResultBothPointerWithConstResult, ConstructingError) { - Result result(&dummyError); - TestError(&result, &dummyError); + Result result(std::make_unique(dummyError)); + TestError(&result, dummyError); } -// Test moving an error Result +// Test moving an error Result TEST(ResultBothPointerWithConstResult, MovingError) { - Result result(&dummyError); - Result movedResult(std::move(result)); - TestError(&movedResult, &dummyError); + Result result(std::make_unique(dummyError)); + Result movedResult(std::move(result)); + TestError(&movedResult, dummyError); } // Test returning an error Result TEST(ResultBothPointerWithConstResult, ReturningError) { - auto CreateError = []() -> Result { return {&dummyError}; }; + auto CreateError = []() -> Result { + return {std::make_unique(dummyError)}; + }; - Result result = CreateError(); - TestError(&result, &dummyError); + Result result = CreateError(); + TestError(&result, dummyError); } // Test constructing a success Result TEST(ResultBothPointerWithConstResult, ConstructingSuccess) { - Result result(&dummyConstSuccess); + Result result(&dummyConstSuccess); TestSuccess(&result, &dummyConstSuccess); } // Test moving a success Result TEST(ResultBothPointerWithConstResult, MovingSuccess) { - Result result(&dummyConstSuccess); - Result movedResult(std::move(result)); + Result result(&dummyConstSuccess); + Result movedResult(std::move(result)); TestSuccess(&movedResult, &dummyConstSuccess); } // Test returning a success Result TEST(ResultBothPointerWithConstResult, ReturningSuccess) { - auto CreateSuccess = []() -> Result { return {&dummyConstSuccess}; }; + auto CreateSuccess = []() -> Result { return {&dummyConstSuccess}; }; - Result result = CreateSuccess(); + Result result = CreateSuccess(); TestSuccess(&result, &dummyConstSuccess); } @@ -212,47 +208,45 @@ TEST(ResultBothPointerWithConstResult, ReturningSuccess) { // Test constructing an error Result TEST(ResultGeneric, ConstructingError) { - Result, int*> result(&dummyError); - TestError(&result, &dummyError); + Result, int> result(std::make_unique(dummyError)); + TestError(&result, dummyError); } // Test moving an error Result TEST(ResultGeneric, MovingError) { - Result, int*> result(&dummyError); - Result, int*> movedResult(std::move(result)); - TestError(&movedResult, &dummyError); + Result, int> result(std::make_unique(dummyError)); + Result, int> movedResult(std::move(result)); + TestError(&movedResult, dummyError); } // Test returning an error Result TEST(ResultGeneric, ReturningError) { - auto CreateError = []() -> Result, int*> { - return {&dummyError}; + auto CreateError = []() -> Result, int> { + return {std::make_unique(dummyError)}; }; - Result, int*> result = CreateError(); - TestError(&result, &dummyError); + Result, int> result = CreateError(); + TestError(&result, dummyError); } // Test constructing a success Result TEST(ResultGeneric, ConstructingSuccess) { - Result, int*> result({1.0f}); + Result, int> result({1.0f}); TestSuccess(&result, {1.0f}); } // Test moving a success Result TEST(ResultGeneric, MovingSuccess) { - Result, int*> result({1.0f}); - Result, int*> movedResult(std::move(result)); + Result, int> result({1.0f}); + Result, int> movedResult(std::move(result)); TestSuccess(&movedResult, {1.0f}); } // Test returning a success Result TEST(ResultGeneric, ReturningSuccess) { - auto CreateSuccess = []() -> Result, int*> { - return {{1.0f}}; - }; + auto CreateSuccess = []() -> Result, int> { return {{1.0f}}; }; - Result, int*> result = CreateSuccess(); + Result, int> result = CreateSuccess(); TestSuccess(&result, {1.0f}); } diff --git a/src/tests/white_box/VulkanErrorInjectorTests.cpp b/src/tests/white_box/VulkanErrorInjectorTests.cpp index 938bd5dd72..bd4a49e1ae 100644 --- a/src/tests/white_box/VulkanErrorInjectorTests.cpp +++ b/src/tests/white_box/VulkanErrorInjectorTests.cpp @@ -61,7 +61,7 @@ TEST_P(VulkanErrorInjectorTests, InjectErrorOnCreateBuffer) { if (err.IsError()) { // The handle should never be written to, even for mock failures. EXPECT_EQ(buffer, VK_NULL_HANDLE); - delete err.AcquireError(); + err.AcquireError(); return false; } EXPECT_NE(buffer, VK_NULL_HANDLE);