-
Notifications
You must be signed in to change notification settings - Fork 546
CXX-3222 add UBSan coverage with extra alignment and fix extended alignment issues #1329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nicely done. LGTM with a suggestion to reduce the storage size.
src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/private/aligned_storage.hh
Outdated
Show resolved
Hide resolved
Validation is blocked on #1332. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that alignof
gives a different answer if the operand is a template parameter is beyond horrifying, but oh well.
LGTM.
Summary
Resolves CXX-3222. Extends UBSan task coverage to include extra alignment configurations and addresses UBSan runtime errors due to aligned allocation requriement violations when the C Driver is configured to use extra alignment.
Important
The solution proposed in this PR is a temporary measure that is only required until CDRIVER-2813 is resolved.
Motivation
Attempting to extend UBSan task coverage to extra alignment configurations as part of #1328 revealed runtime alignment errors:
The root cause of this problem is that
operator new
does not support extended alignment until C++17 viastd::align_val_t
.Support for extended alignment is implementation-defined prior to C++17. Many implementations do not support it.
operator new
often only supports alignment up toalignof(std::max_align_t)
.Furthermore, this problem is viral: any parent class which contains a data member with extended alignment requirements inherits those extended alignment requirements:
Neither
alignas
norstd::aligned_storage
are viable workarounds, as they only apply alignment requirements the object or data member itself, which does not improve the status quo, as the parent object may still be allocated viaoperator new
, in which case the allocation function remains oblivious to the extended alignment requirements:Proposed Solution
To address this problem without leaking custom allocation details into the ABI (that is, preserving the current type of
std::unique_ptr<impl>
data members), a newbsoncxx::aligned_storage<T>
helper is introduced to avoid leaking extended alignment requirements to parent objects. By reserving x2 the size ofT
and usingstd::align
to obtain an aligned pointer into the reserved storage region, correct alignment is guaranteed, but at the cost ofx2an additionalalignof(T)
bytes more than is normally required for the allocated object.Important
This workaround reserves
x2an additionalalignof(T)
bytes more than is normally required for the allocated object.Note
This is only required for objects or data members which may be dynamically allocated via
operator new
. Stack-allocated objects do not require this workaround (i.e. all current usage ofscoped_bson_t
). AFAICT this is currently limited to themanaged_bson_t
,builder::core::impl::frame
, andclient_session::impl
classes.Attempting to use
alignof(T)
withinaligned_storage<T>
does not reliably produce desired behavior, as observed with Clang 12.0.1 on RHEL 8.0:Inspection reveals
alignof(T) == 4
despiteT = bson_t
andalignof(bson_t) == 128
. It is unclear if this is a compiler bug. I am unable to reproduce this behavior locally or with Compiler Explorer. I suspect the cause is that template parameters may not inherit attributes on some compilers or compiler versions, which may includes thealigned
attribute, as indicated by GCC 13.3:Therefore,
aligned_storage
is defined in terms of size and alignment only, not onT
.Because attributes do not appear to be inherited by template parameters, types with extended alignment such as
bson_t
need to be "explicit" for the compiler to see and deduce extended alignment requirements to resulting pointers. For example:libmongoc::uri_get_options
mocksbson_t* mongoc_uri_get_options(mongoc_uri_t const* uri)
by providing a function call operator overload which returnsbson_t*
. However, because the return type is specified in terms of a template parameterR
, pertemplate <typename R, typename... Args> class mock<R(MONGOCXX_ABI_CDECL*)(Args...)>
, the compiler fails to observe the extended alignment attributes forbson_t*
. The resultingopts_bson
pointer, when passed tobson_get_data
, is assumed to have a fundamental alignment of4
rather than an extended alignment of128
, producing the warning above. The solution is therefore to explicitly specialize and overload with an explicit reference tobson_t*
in its declaration (not via a template parameter) to preserve alignment attributes.