Date: | December 23, 2015 / year-entry #270 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20151223-00/?p=92701 |
Comments: | 12 |
Summary: | It's just an untyped pointer. |
There is a structure called a
There is also a structure called a
And then there is a type called
typedef PVOID PSECURITY_DESCRIPTOR; // equivalent to // typedef void *PSECURITY_DESCRIPTOR;
Most code that accept security descriptors don't care
whether the security descriptor is absolute or relative.
They just pass the security descriptor through to functions
like
You rarely notice this switcheroo because code that deals with
security descriptors typically use helper functions to do the
heavy lifting.
You notice this problem if you try to use something like
template<typename T> struct LocalAlloc_delete { LocalAlloc_delete() { } void operator()(T* p) throw() { LocalFree(p); } }; template<typename T> using unique_localptr = std::unique_ptr<T, LocalAlloc_delete<T>>; void some_function() { PSECURITY_DESCRIPTOR result; ConvertStringSecurityDescriptorToSecurityDescriptorW( L"O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)", SDDL_REVISION_1, &result, nullptr); // compiler error here unique_localptr<SECURITY_DESCRIPTOR> sd(result); .. do stuff with sd ... }
The compiler complains because I can't think of a clean way out of this. Here are some ugly ways out: // ugly option 1 - cast it away unique_localptr<SECURITY_DESCRIPTOR> sd(reinterpret_cast<SECURITY_DESCRIPTOR*>(result)); // ugly option 2 - special knowledge about PSECURITY_DESCRIPTOR unique_localptr<void> sd(result); // ugly option 3 - general, but an awful lot of typing unique_localptr< std::remove_pointer<PSECURITY_DESCRIPTOR>::type> sd(result);
In retrospect, the structure for an absolute security
descriptor should have been named
|
Comments (12)
Comments are closed. |
I guess that’s the problem with C being the primary language of the Windows API, because in C++ this would probably have been solved with a base class and two derived classes…
//Nitpicker’s corner
Why use a reinterpret_cast from void*, where a static_cast would suffice?
You know that Raymond is a fan of reinterpret_cast, don’t you? It’s like more brutal and dangerous variant of C-cast, while you can pretend you enjoy type safety of C++.
I use
static_cast
when I’m converting between related pointers. Butvoid*
isn’t related to anything, so I usereinterpret_cast
to emphasize “This is scary, you’d better be right because the compiler isn’t going to help.”I always end up seeing it in the opposite way. Because of that implicit conversion to void *, it is actually related to everything.
Of course, the result is the same. You are going to have to be really sure when you cast it back, otherwise bad things are going to happen.
I was just mentioning this because it was interesting how a differing point of view ended up with the same result.
I tend to use
static_cast
for “The compiler will double-check me here” andreinterpret_cast
for “Pay close attention here.” Although you can technically usestatic_cast
withvoid*
, I think it’s misleading and lets you hide a dangerous cast inside something that looks safe.It’s a pity that there is no compiler flag to mark all casts from void* (including typedef’ed) as dangerous. I’d also follow such cast with some assert() wherever possible.
There is another option. unique_ptr has a nifty feature where the managed pointer type can be switched from T* to Deleter::pointer if that type exists. So just provide a specialization of LocalAlloc_delete for SECURITY_DESCRIPTOR
template
struct LocalAlloc_delete
{
void operator()(PSECURITY_DESCRIPTOR p) const throw( )
{
LocalFree(p);
}
using pointer = PSECURITY_DESCRIPTOR;
};
Now unique_localptr will happily accept a PSECURITY_DESCRIPTOR
http://rextester.com/UOC70003
Obviously I have no clue how to do code formatting in comments.
I don’t think you can, so don’t worry. (P.S., cool trick.)
No problem, just change it to what’s expected.
Instead of:
template using unique_localptr = std::unique_ptr<T, LocalAlloc_delete>;
…
unique_localptr sd(result);
why not
template
std::unique_ptr<T, LocalAlloc_delete> unique_localptr(T* raw_ptr)
{
return std::unique_ptr<T, LocalAlloc_delete>(raw_ptr);
}
…
auto sd(unique_localptr(result));
Wouldn’t it have been better to name the generic security descriptor SECURITY_DESCRIPTOR_GENERIC and create a SECURITY_DESCRIPTOR_ABSOLUTE alias for SECURITY_DESCRIPTOR (keeping the old name around for compatibility)?