From efc2f0fde712d1bb6e4bd2c1d228cb3ff70b9247 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 11 Jan 2025 22:55:21 -0600 Subject: [PATCH] Fix reading past end of array. Fix a bug in the `NonDelegatingGetIids()` implementation that could cause reading past the end of the returned array. `std::copy()` returns a pointer to the next element in the array after the last element copied. The output argument `*array` was being assinged to this pointer after the first copy, causing it to no longer point to the beginning of the array. If the caller tries to access the full array after this, it will read past the end of the array and will miss the first elements of the array. To fix, introduce a new temporary `_array` variable to pass the result of the first copy as the starting point of the second copy. Also add a test that failed before the fix and passes after the fix. --- strings/base_implements.h | 4 ++-- test/old_tests/UnitTests/Composable.cpp | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/strings/base_implements.h b/strings/base_implements.h index b620c6a6a..061a98125 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -1033,8 +1033,8 @@ namespace winrt::impl { return error_bad_alloc; } - *array = std::copy(local_iids.second, local_iids.second + local_count, *array); - std::copy(inner_iids.cbegin(), inner_iids.cend(), *array); + auto _array = std::copy(local_iids.second, local_iids.second + local_count, *array); + std::copy(inner_iids.cbegin(), inner_iids.cend(), _array); } else { diff --git a/test/old_tests/UnitTests/Composable.cpp b/test/old_tests/UnitTests/Composable.cpp index 3cbc283d6..6b0a30dd3 100644 --- a/test/old_tests/UnitTests/Composable.cpp +++ b/test/old_tests/UnitTests/Composable.cpp @@ -167,4 +167,20 @@ TEST_CASE("Composable conversions") { TestCalls(*make_self()); TestCalls(*make_self()); -} \ No newline at end of file +} + +TEST_CASE("Composable get_interfaces") +{ + struct Foo : Composable::BaseT { + hstring ToString() const { return L"Foo"; } + }; + + auto obj = make(); + auto iids = winrt::get_interfaces(obj); + // BaseOverrides IID gets repeated twice. There are only 4 unique interfaces. + REQUIRE(iids.size() >= 4); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); +}