`deserialize_into()` example contains undefined behavior

Issue #194 resolved
Dan Bonachea created an issue

The 2022.3.0 spec contains this example for deserializing_iterator<T>::deserialize_into():

  BigObject *ptr = /* ... */;
  future<> = rpc( target_rank,
    [](view<BigObject> item) {
      auto storage =
       new typename std::aligned_storage<sizeof(BigObject),
                                         alignof(BigObject)>::type;
      BigObject *ptr = item.begin().deserialize_into(storage);
      /* consume the object */
      delete ptr;
    },
    make_view(ptr, ptr+1));

@Amir Kamil has pointed out that this idiom technically contains undefined behavior, because it invokes a C++ new expression with one type (creating an object of type std::aligned_storage<...>::type) and the corresponding delete expression uses a pointer of a different type (destroying an object of type BigObject).

The relevant text from C++11 [expr.delete]: (emphasis added)

In the first alternative (delete object), the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10) . If not, the behavior is undefined.

Where the "non-array object created by the previous new-expression" would be an std::aligned_storage<...>::type object, which is not the same object type as BigObject nor part of an inheritance hierachy with it (hence UB).

We are not aware of any implementation where this distinction causes a problem, but we should fix our example idiom (and test code modeled on it) to remove the UB.

Comments (1)

  1. Log in to comment