Sanitizer and "downcast of address 0xXX...XXX with insufficient space for an object of type '_Rb_tree_node' "

Hi All,

What is this finding trying to tell me.

The iterator is a typedef for _Base_ptr, and the address of _M_header
is a pointer. _Link_type is typedef'd as a _Rb_tree_node<_Tp>*. So I
don't see a width problem.

Hi All,

What is this finding trying to tell me.

The iterator is a typedef for _Base_ptr, and the address of _M_header
is a pointer.

What type is _M_header? How big is it? I think it's telling you that
_M_header is too small to possibly be a _Link_type.

I've not looked at the code, but a typical implementation for
iterators/end() for a node-based container is that they return a
[wrapper for a] Node* which actually points only to a base class of a
Node, knowing that it will be casted back to the correct type before
any permitted use (e.g., dereferencing it is undefined behavior).
That's valid, and yet seems like a pretty reasonable thing for a
sanitizer to catch -- the Node* does not point to a Node. It's
arguably a false positive, but I don't see how any automated tool
could reasonably know that unless it has some kind of whitelist.

-- James

Hi All,

What is this finding trying to tell me.

The iterator is a typedef for _Base_ptr, and the address of _M_header
is a pointer. _Link_type is typedef’d as a _Rb_tree_node<_Tp>*. So I
don’t see a width problem.

_M_header is an _Rb_tree_node_base, which is smaller than an _Rb_tree_node<_Tp>. Usually, this would be OK – you can reinterpret_cast between pointers of different types pretty much arbitrarily – but because _Rb_tree_node_base is a base class of _Rb_tree_node<_Tp>, this is a static_cast, and the ruling wording is 5.2.9/11, which says " If the prvalue of type “pointer to cv1 B” points
to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined."

We’ve managed to prove that the prvalue of type “pointer to _Rb_tree_node_base” is not, in fact, a subobject of type “_Rb_tree_node<_Tp>”, because there’s not enough room in the allocated storage for an object of that type at that address. So we’ve determined that the behavior is undefined.

This is a bug in libstdc++. The fix is to use reinterpret_cast instead of static_cast in the definition of ‘end’.