Skip to content

Commit 7bc7df6

Browse files
authored
Fix reading past end of array. (#1468)
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.
1 parent fd0e959 commit 7bc7df6

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

strings/base_implements.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,8 +1033,8 @@ namespace winrt::impl
10331033
{
10341034
return error_bad_alloc;
10351035
}
1036-
*array = std::copy(local_iids.second, local_iids.second + local_count, *array);
1037-
std::copy(inner_iids.cbegin(), inner_iids.cend(), *array);
1036+
auto next = std::copy(local_iids.second, local_iids.second + local_count, *array);
1037+
std::copy(inner_iids.cbegin(), inner_iids.cend(), next);
10381038
}
10391039
else
10401040
{

test/old_tests/UnitTests/Composable.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,20 @@ TEST_CASE("Composable conversions")
167167
{
168168
TestCalls(*make_self<Foo>());
169169
TestCalls(*make_self<Bar>());
170-
}
170+
}
171+
172+
TEST_CASE("Composable get_interfaces")
173+
{
174+
struct Foo : Composable::BaseT<Foo, IStringable> {
175+
hstring ToString() const { return L"Foo"; }
176+
};
177+
178+
auto obj = make<Foo>();
179+
auto iids = winrt::get_interfaces(obj);
180+
// BaseOverrides IID gets repeated twice. There are only 4 unique interfaces.
181+
REQUIRE(iids.size() == 5);
182+
REQUIRE(std::find(iids.begin(), iids.end(), guid_of<IBase>()) != iids.end());
183+
REQUIRE(std::find(iids.begin(), iids.end(), guid_of<IBaseProtected>()) != iids.end());
184+
REQUIRE(std::find(iids.begin(), iids.end(), guid_of<IBaseOverrides>()) != iids.end());
185+
REQUIRE(std::find(iids.begin(), iids.end(), guid_of<IStringable>()) != iids.end());
186+
}

0 commit comments

Comments
 (0)