C++ Logo


Advanced search

Re: Poisoned initializers

From: Ville Voutilainen <ville.voutilainen_at_[hidden]>
Date: Sat, 12 Jun 2021 13:03:14 +0300
On Sat, 12 Jun 2021 at 08:04, Tom Honermann via Std-Proposals
<std-proposals_at_[hidden]> wrote:
> Accessing uninitialized variables or data members is a well known source of undefined behavior (UB). The fact that such accesses result in UB is leveraged by tools like MemorySanitizer to diagnose such accesses. Programmers that use these tools may resist adding initializers when a default value is not desirable since doing so prevents diagnosing an unintended access before an appropriate value has been determined and assigned. This results in undesirable compiler warnings or static analysis complaints about uninitialized variables or data members (undesirable because the omission is intentional). Worse, if such an access is not diagnosed and corrected, the program will exhibit UB at run-time.
> This situation could perhaps be improved by allowing an initializer to be "poisoned". The idea is that, when code is compiled for use with a tool like MemorySanitizer, the initializer is effectively discarded or the assigned object value otherwise marked as invalid so as to enable diagnosing an invalid access. But when compiled normally, the provided initializer is used so as to avoid UB and ensure consistent behavior at run-time (though that behavior may still be wrong according to programmer intentions).
> For example:
> struct S {
> S() {}
> S(int v) : dm(v) {}
> // dm may only be used if a value was provided during construction.
> int dm = POISON(-1);
> };
> int f(bool b) {
> S s = b ? S() : S(42);
> // The following access of s.dm violates preconditions if b is true.
> // Would like MemorySanitizer to diagnose as an access of an uninitialized
> // data member. But if MemorySanitizer is not enabled, then would like to
> // reliably return -1.
> return s.dm;
> }
> Implementation would presumably require POISON() to be implemented via a keyword or intrinsic function. Perhaps there is a clever way to implement it as a library function.
> Worth pursuing? Prior art?

There has been multiple previous discussions about explicit marking a
variable uninitialized, but I think this is a new twist
on the idea. I wonder, considering that the initializer value is used
unless compilation for a tool decides otherwise,
why this isn't just

int dm [[poisoned]] = -1;
[[poisoned]] int dm = -1;
if that position is your cup of tea.

The implementation would recognize the attribute and mark the variable
for sanitizing or discard the initializer if built for a sanitizer,
and otherwise just use the initializer.

Received on 2021-06-12 05:03:28