Skip to content

Commit e347c60

Browse files
authored
Do not pass nullptr arrays to the ABI (#541)
1 parent a7ed103 commit e347c60

File tree

7 files changed

+129
-37
lines changed

7 files changed

+129
-37
lines changed

strings/base_array.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,15 @@ WINRT_EXPORT namespace winrt
353353
template <typename T>
354354
auto get_abi(array_view<T> object) noexcept
355355
{
356+
auto data = object.size() ? object.data() : (T*)alignof(T);
357+
356358
if constexpr (std::is_base_of_v<Windows::Foundation::IUnknown, T>)
357359
{
358-
return (void**)object.data();
360+
return (void**)data;
359361
}
360362
else
361363
{
362-
return reinterpret_cast<impl::arg_out<std::remove_const_t<T>>>(const_cast<std::remove_const_t<T>*>(object.data()));
364+
return reinterpret_cast<impl::arg_out<std::remove_const_t<T>>>(const_cast<std::remove_const_t<T>*>(data));
363365
}
364366
}
365367

test/test/in_params.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ TEST_CASE("in_params")
4444
REQUIRE(object.InStructArray({ {L"1",L"2"}, {L"3",L"4"} }) == L"1234");
4545
REQUIRE(object.InEnumArray({ Signed::First, Signed::Second }) == L"FirstSecond");
4646

47+
// Ensure 0-length arrays are passed as non-null pointers to the ABI,
48+
// in order to keep RPC happy.
49+
REQUIRE(object.InInt32Array({ }) == L"");
50+
REQUIRE(object.InStringArray({ }) == L"");
51+
REQUIRE(object.InObjectArray({ }) == L"");
52+
REQUIRE(object.InStringableArray({ }) == L"");
53+
REQUIRE(object.InStructArray({ }) == L"");
54+
REQUIRE(object.InEnumArray({ }) == L"");
55+
4756
// params::hstring optimizations
4857
REQUIRE(object.InString(L"") == L"");
4958
REQUIRE(object.InString({}) == L"");

test/test/out_params.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ TEST_CASE("out_params")
151151
REQUIRE(value[1] == Signed::Second);
152152
REQUIRE(value[2] == static_cast<Signed>(0));
153153
}
154+
// Ensure 0-length arrays are passed as non-null pointers to the ABI,
155+
// in order to keep RPC happy.
156+
{
157+
REQUIRE_NOTHROW(object.RefInt32Array({}));
158+
REQUIRE_NOTHROW(object.RefStringArray({}));
159+
REQUIRE_NOTHROW(object.RefObjectArray({}));
160+
REQUIRE_NOTHROW(object.RefStringableArray({}));
161+
REQUIRE_NOTHROW(object.RefStructArray({}));
162+
REQUIRE_NOTHROW(object.RefEnumArray({}));
163+
}
154164

155165
object.Fail(true);
156166

test/test_component/Class.cpp

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ namespace winrt::test_component::implementation
207207

208208
hstring Class::InInt32Array(array_view<int32_t const> value)
209209
{
210+
simulate_rpc_behavior(value);
211+
210212
hstring result;
211213

212214
for (auto&& v : value)
@@ -218,6 +220,8 @@ namespace winrt::test_component::implementation
218220
}
219221
hstring Class::InStringArray(array_view<hstring const> value)
220222
{
223+
simulate_rpc_behavior(value);
224+
221225
hstring result;
222226

223227
for (auto&& v : value)
@@ -229,6 +233,8 @@ namespace winrt::test_component::implementation
229233
}
230234
hstring Class::InObjectArray(array_view<Windows::Foundation::IInspectable const> value)
231235
{
236+
simulate_rpc_behavior(value);
237+
232238
hstring result;
233239

234240
for (auto&& v : value)
@@ -240,6 +246,8 @@ namespace winrt::test_component::implementation
240246
}
241247
hstring Class::InStringableArray(array_view<Windows::Foundation::IStringable const> value)
242248
{
249+
simulate_rpc_behavior(value);
250+
243251
hstring result;
244252

245253
for (auto&& v : value)
@@ -251,6 +259,8 @@ namespace winrt::test_component::implementation
251259
}
252260
hstring Class::InStructArray(array_view<Struct const> value)
253261
{
262+
simulate_rpc_behavior(value);
263+
254264
hstring result;
255265

256266
for (auto&& v : value)
@@ -262,6 +272,8 @@ namespace winrt::test_component::implementation
262272
}
263273
hstring Class::InEnumArray(array_view<Signed const> value)
264274
{
275+
simulate_rpc_behavior(value);
276+
265277
hstring result;
266278

267279
for (auto&& v : value)
@@ -304,68 +316,98 @@ namespace winrt::test_component::implementation
304316

305317
void Class::RefInt32Array(array_view<int32_t> value)
306318
{
307-
int32_t counter{};
319+
simulate_rpc_behavior(value);
320+
321+
if (value.size())
322+
{
323+
int32_t counter{};
308324

309-
std::generate(value.begin(), value.end() - 1, [&]
310-
{
311-
return ++counter;
312-
});
325+
std::generate(value.begin(), value.end() - 1, [&]
326+
{
327+
return ++counter;
328+
});
329+
}
313330
}
314331

315332
void Class::RefStringArray(array_view<hstring> value)
316333
{
317-
int32_t counter{};
334+
simulate_rpc_behavior(value);
335+
336+
if (value.size())
337+
{
338+
int32_t counter{};
318339

319-
std::generate(value.begin(), value.end() - 1, [&]
320-
{
321-
return hstring{ std::to_wstring(++counter) };
322-
});
340+
std::generate(value.begin(), value.end() - 1, [&]
341+
{
342+
return hstring{ std::to_wstring(++counter) };
343+
});
344+
}
323345
}
324346

325347
void Class::RefObjectArray(array_view<Windows::Foundation::IInspectable> value)
326348
{
327-
int32_t counter{};
349+
simulate_rpc_behavior(value);
328350

329-
std::generate(value.begin(), value.end() - 1, [&]
330-
{
331-
return make<Value>(++counter);
332-
});
351+
if (value.size())
352+
{
353+
int32_t counter{};
354+
355+
std::generate(value.begin(), value.end() - 1, [&]
356+
{
357+
return make<Value>(++counter);
358+
});
359+
}
333360
}
334361

335362
void Class::RefStringableArray(array_view<Windows::Foundation::IStringable> value)
336363
{
337-
int32_t counter{};
364+
simulate_rpc_behavior(value);
338365

339-
std::generate(value.begin(), value.end() - 1, [&]
340-
{
341-
return make<Value>(++counter);
342-
});
366+
if (value.size())
367+
{
368+
int32_t counter{};
369+
370+
std::generate(value.begin(), value.end() - 1, [&]
371+
{
372+
return make<Value>(++counter);
373+
});
374+
}
343375
}
344376

345377
void Class::RefStructArray(array_view<Struct> value)
346378
{
347-
int32_t counter{};
379+
simulate_rpc_behavior(value);
348380

349-
std::generate(value.begin(), value.end() - 1, [&]
350-
{
351-
return Struct
381+
if (value.size())
382+
{
383+
int32_t counter{};
384+
385+
std::generate(value.begin(), value.end() - 1, [&]
352386
{
353-
hstring{ std::to_wstring(++counter) },
354-
hstring{ std::to_wstring(++counter) }
355-
};
356-
});
387+
return Struct
388+
{
389+
hstring{ std::to_wstring(++counter) },
390+
hstring{ std::to_wstring(++counter) }
391+
};
392+
});
393+
}
357394
}
358395

359396
void Class::RefEnumArray(array_view<Signed> value)
360397
{
361-
Signed counter{ Signed::First };
398+
simulate_rpc_behavior(value);
362399

363-
std::generate(value.begin(), value.end() - 1, [&]
364-
{
365-
auto result = counter;
366-
counter = static_cast<Signed>(static_cast<int32_t>(counter) + 1);
367-
return result;
368-
});
400+
if (value.size())
401+
{
402+
Signed counter{ Signed::First };
403+
404+
std::generate(value.begin(), value.end() - 1, [&]
405+
{
406+
auto result = counter;
407+
counter = static_cast<Signed>(static_cast<int32_t>(counter) + 1);
408+
return result;
409+
});
410+
}
369411
}
370412

371413
com_array<int32_t> Class::ReturnInt32Array()

test/test_component/Class.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ namespace winrt::test_component::implementation
115115

116116
bool m_fail{};
117117
event<Windows::Foundation::TypedEventHandler<test_component::Class, test_component::DeferrableEventArgs>> m_deferrableEvent;
118+
119+
template<typename T>
120+
static void simulate_rpc_behavior(array_view<T> const& value)
121+
{
122+
// RPC requires array pointers to be non-null.
123+
if (value.begin() == nullptr)
124+
{
125+
throw hresult_error(static_cast<hresult>(0x800706f4)); // HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER)
126+
}
127+
}
118128
};
119129

120130
struct DeferrableEventArgs : DeferrableEventArgsT<DeferrableEventArgs>, deferrable_event_args<DeferrableEventArgs>

test/test_win7/in_params.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ TEST_CASE("in_params")
4444
REQUIRE(object.InStructArray({ {L"1",L"2"}, {L"3",L"4"} }) == L"1234");
4545
REQUIRE(object.InEnumArray({ Signed::First, Signed::Second }) == L"FirstSecond");
4646

47+
// Ensure 0-length arrays are passed as non-null pointers to the ABI,
48+
// in order to keep RPC happy.
49+
REQUIRE(object.InInt32Array({ }) == L"");
50+
REQUIRE(object.InStringArray({ }) == L"");
51+
REQUIRE(object.InObjectArray({ }) == L"");
52+
REQUIRE(object.InStringableArray({ }) == L"");
53+
REQUIRE(object.InStructArray({ }) == L"");
54+
REQUIRE(object.InEnumArray({ }) == L"");
55+
4756
// params::hstring optimizations
4857
REQUIRE(object.InString(L"") == L"");
4958
REQUIRE(object.InString({}) == L"");

test/test_win7/out_params.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ TEST_CASE("out_params")
151151
REQUIRE(value[1] == Signed::Second);
152152
REQUIRE(value[2] == static_cast<Signed>(0));
153153
}
154+
// Ensure 0-length arrays are passed as non-null pointers to the ABI,
155+
// in order to keep RPC happy.
156+
{
157+
REQUIRE_NOTHROW(object.RefInt32Array({}));
158+
REQUIRE_NOTHROW(object.RefStringArray({}));
159+
REQUIRE_NOTHROW(object.RefObjectArray({}));
160+
REQUIRE_NOTHROW(object.RefStringableArray({}));
161+
REQUIRE_NOTHROW(object.RefStructArray({}));
162+
REQUIRE_NOTHROW(object.RefEnumArray({}));
163+
}
154164

155165
object.Fail(true);
156166

0 commit comments

Comments
 (0)