Last time, we fixed the problem of creating a unique_ptr whose deleter’s constructor was might throw an exception. But we’re not out of the woods yet.
Let’s take another look at what we have:
if (d.try_as<::INoMarshal>()) {
void* p;
if constexpr (std::is_reference_v<Delegate>) {
p = winrt::detach_abi(d);
} else {
winrt::copy_to_abi(d, p);
}
return
[p = std::unique_ptr<void, in_context_deleter>(p, {}),
token = get_context_token()](auto&&...args) {
if (token == get_context_token()) {
std::remove_reference_t<Delegate> d;
winrt::copy_from_abi(d, p.get());
d(std::forward<decltype(args)>(args)...);
} else {
throw winrt::hresult_error(CO_E_NOT_SUPPORTED);
}
};
}
We had originally broken the rule that the unique_ptr(p) constructor requires that the deleter’s default constructor not throw an exception. We fixed it by constructing the deleter explicitly as a parameter, so that the unique_ptr constructor can move it into the stored deleter without an exception.
But wait, if an exception occurs in construction of the in_, the raw pointer we created in the previous block will be leaked. It owns a reference count but doesn’t clean up in the case of an exception.
We can fix this by creating the deleter first.
if (d.try_as<::INoMarshal>()) {
in_context_deleter del;
void* p;
if constexpr (std::is_reference_v<Delegate>) {
p = winrt::detach_abi(d);
} else {
winrt::copy_to_abi(d, p);
}
return
[p = std::unique_ptr<void, in_context_deleter>(p, std::move(del)),
token = get_context_token()](auto&&...args) {
if (token == get_context_token()) {
std::remove_reference_t<Delegate> d;
winrt::copy_from_abi(d, p.get());
d(std::forward<decltype(args)>(args)...);
} else {
throw winrt::hresult_error(CO_E_NOT_SUPPORTED);
}
};
}
If there is an exception constructing the custom deleter, it happens before we initialze the raw pointer, so there is no leak of the reference owned by that raw pointer.
Okay, so are we done now?
Nope.
More next time.
@Raymond Chen:
I have a question unrelated to this topic and I hope you will investigate it when you have time.
You know that Microsoft.UniversalStore.HardwareWorkflow.SubmissionBuilder.dll (along with InfReader, Catalogs, Cabinets) used by Inf2Cat.exe?
Whoever wrote it must have been out of their god damn mind because the way it works is -- it parses all infs and driver files into a giant XML and uses that to generate the catalog file.
If you run it on an unpacked NVIDIA Display.Driver folder to regenerate the catalog it will create 260.52 MB XML file and spend north of 15 minutes creating a catalog because it is...
Tip: Insulting people is generally not an effective way to get them to do you a favor.
I updated the "insult" to past tense to allow for the possibility that they came to their senses in the meantime.
As for the favor part, it's not like I was asking for a fix -- I am long past expecting anytthing good code-wise and API wise coming out from Microsoft and I have a feeling that if it weren't for you Windows would have been nothing more than a random collection of BSODs.
You are of course free to do anything you want with the above info including ignoring it or getting offended by me pointing out the architectural issue (which...