C++ false positives about uninitialized data surrounding new-placement and std::addressof

I have a small optional implementation that has been triggering constant false-positives from sonar, essentially along the lines of:

template<typename T>
class optional {
    union {
        char x;
        T uvalue;
    };
    bool holds_value = false;
public:
    optional() = default;
    optional(const optional&) = delete;
    optional(optional&&) = delete;
    optional& operator=(const optional&) = delete;
    optional& operator=(optional&&) = delete;
    template<typename U = T>
    explicit optional(U&& value) : holds_value(true) {
        new (static_cast<void*>(std::addressof(uvalue))) T(std::forward<U>(value));
    }
    explicit operator bool() const {
        return holds_value;
    }
    T& unwrap() & {
        assert(holds_value && "Optional does not contain a value");
        return uvalue;
    }
};

Stepping through the simulated execution flow it appears the smoking gun is that sonar thinks the constructor does not write to uvalue:

	↳  1 Calling constructor for 'optional<int>'
	↳  2 Returning without writing to 'this->.uvalue'
	↳  3 Returning from constructor for 'optional<int>'

Here is a reproduction: Compiler Explorer.

If I remove the std::address_of sonar does not complain: Compiler Explorer.

Hey there!

What version of SonarLint are you using, and in what IDE?

Hi @jeremy-rifkin, long time no see!

Thanks for your valuable report. I know what’s going on :smiley:
We don’t model (yet) std::addressof, but it should be fairly easy to address.

Funnily enough, if they had used the operator& or the __builtin_addressof() then it would have worked!

An alternative way to fix this would be to force inlining some well-known functions so that the engine could track the value flows.

I’ve created the CPP-5358 ticket to track this.

2 Likes

Sweet thank you both so much!