[Mesa-dev] [RFC PATCH 0/5] Safer way to ralloc C++ objects.

Francisco Jerez currojerez at riseup.net
Thu Oct 10 05:32:29 CEST 2013


This patch series tries out a different approach to allocating C++
objects from an ralloc context.  It's independent to the last series I
sent earlier today [1] -- which probably makes sense on its own
because it's a more incremental improvement and is likely to take less
time to discuss and review.

Overriding operator new and delete to allocate from a hierarchical
allocation context is inherently unsafe because there's no reasonable
way for the placement new operator to find out what the actual type of
the object being allocated is, and there's no reasonable way to call
the destructor when the object released.  The following code from the
DECLARE_RALLOC_CXX_OPERATORS macro:

| static void _ralloc_destructor(void *p)
| {
|    reinterpret_cast<TYPE *>(p)->~TYPE();
| }

has undefined behavior because if the original TYPE has been
subclassed TYPE is likely not to be the actual allocation type of the
object, and we will be reinterpreting a void pointer to the derived
type as a pointer to the base type, which is wrong and will almost
certainly cause a crash if the conversion requires a pointer
adjustment -- This is especially dangerous in presence of multiple or
virtual inheritance, but it's not guaranteed to work in any case.

Another problem arises if the ralloc operator overrides are defined in
a non-polymorphic base class, say 'exec_node', and the derived class,
say 'ir_instruction', implements a non-trivial destructor.  The
correct destructor will never be called because for ralloc the object
type is always just 'exec_node'.

To solve this I've replaced all uses of the overridden new and delete
operators with calls to new helper functions ralloc_new<>() and
ralloc_delete<>().  Allocating an object now looks like:

| T *object = ralloc_new<T>(ralloc_context, first_constructor_argument, ...);
| ...
| ralloc_delete(object);

This has other advantages: The most obvious one is that it reduces the
amount of boilerplate code that is required for ralloc even further,
classes no longer need to be decorated with
DECLARE_RALLOC_CXX_OPERATORS in order to be allocated with ralloc, any
object type can be instantiated with ralloc_new -- memory management
is completely decoupled of the object definition itself, and the
normal and placement built-in new and delete operators are usable
again on objects that used to be ralloc'ed.

The C++11 features I've used seem to be supported on GCC 4.3 or later
[I haven't tested that yet, I don't have such an old version at hand].
The dependency on C++11 is not fundamental though, and if it seems
unreasonable it could be removed by use of the HAS_TRIVIAL_DESTRUCTOR
patch I sent earlier [1] and by making the implementation of
ralloc_new considerably uglier.

Thanks.

[1] http://lists.freedesktop.org/archives/mesa-dev/2013-October/046011.html

[RFC PATCH 1/5] mesa: Compile all C++ users of ralloc as C++11.
[RFC PATCH 2/5] ralloc: Add ralloc_new/delete functions for allocation of C++ objects.
[RFC PATCH 3/5] ralloc: Replace usage of new and delete operator overloads with new helper functions.
[RFC PATCH 4/5] ralloc: Remove overloads of the placement new and delete operator.
[RFC PATCH 5/5] glsl: Remove the virtual destructor of ir_instruction.


More information about the mesa-dev mailing list