<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/110683>110683</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[libc++] Hardened unique_ptr<T[]> incorrectly handles custom deleters
</td>
</tr>
<tr>
<th>Labels</th>
<td>
libc++
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
ldionne
</td>
</tr>
</table>
<pre>
This makes the attached program crash (…in most runs, not 100% of the time):
[unique.cc.zip](https://github.com/user-attachments/files/17196807/unique.cc.zip)
```
% out/gn/bin/clang++ unique.cc -isysroot $(xcrun -show-sdk-path) -std=c++20 -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE
% ./a.out
zsh: trace trap ./a.out
```
lldb shows that this indeed this check:
```
frame #0: 0x00000001000029e4 a.out`std::__1::unique_ptr<std::__1::vector<int, std::__1::allocator<int>> [], AlignedDeleter<std::__1::vector<int, std::__1::allocator<int>>>>::operator[][abi:se200000](unsigned long) const [inlined] __clang_trap_msg$libc++$/Users/thakis/src/llvm-project/out/gn/bin/../include/c++/v1/__memory/unique_ptr.h:566: assertion __checker_.__in_bounds(std::__to_address(__ptr_), __i) failed: unique_ptr<T[]>::operator[](index): index out of range
```
The program uses a unique_ptr with a custom deleter to refer to raw malloc-ed memory, "to allow having uninitialized entries inside it".
It has this typedef:
```
template <typename T>
using AlignedUniquePtr =
std::unique_ptr<T, AlignedDeleter<typename std::remove_extent<T>::type>>;
```
It uses this typedef with an array type:
```
// Underlying storage. It's raw malloc-ed rather than being a unique_ptr<T[]>
// to allow having uninitialized entries inside it.
AlignedUniquePtr<T[]> entries_;
```
It creates objects of this unique_ptr like so:
```
template <typename T>
AlignedUniquePtr<T> AlignedAllocTyped(size_t n_membs) {
using TU = typename std::remove_extent<T>::type;
return AlignedUniquePtr<T>(
static_cast<TU*>(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs)));
}
```
`AlignedAlloc()` is basically malloc – in particular, nothing calls `new[]`, so it doesn't write an array cookie.
The custom deleter looks like so (`AlignedFree()` is just `free()`):
```
template <typename T>
struct AlignedDeleter {
inline void operator()(T* ptr) const { AlignedFree(ptr); }
};
```
The class containing `entries_` calls dtors as needed, and the deleter really only needs to free memory. `delete []` is never called.
Is this a valid use of unique_ptr<T[]>? If so, should this hardening only be used for unique_ptrs that don't have a custom deleter?
_Originally posted by @nico in https://github.com/llvm/llvm-project/issues/91798#issuecomment-2384260976_
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysV19z6roR_zTiZQfGyGDggQf-9mamPfdMSzp988jWgnUjS1SSSTifvrOyIUBO0jntZTyOY6323--3q7XwXh0M4pyNl2y87okmVNbNtVTWGOwVVp7ncPfbVcpDLV7QQ6gQRAiirFDC0dmDEzWUTvgKGJ-yDWfThC0yZaC2PoBrjGd8BcYGGCYJ42Ow-6gkqBoZn7F0wZI1Sy738bIx6t8NDspy8EMd2XjN-LQK4ehJkm8Z3x5UqJpiUNqa8W3j0fVbh2o0wTO-3SuN9Hc4Gc6yaTIhqTudfHZnMku6K_4L0ccmkCHD-LZQdC-1MAfGl4wv4aoM-sqfvbM2AOMjxqdvpWsM9H1lX_tevvSPIlSMz6Dvg2TpumwV8AT66_yvT8vV9-_5b4u_rzffnr79Jf_b7-sNSz9ZyDf_2m2-_ePpn5sISOc5H8OA8a0YkL_x1Q9fsXQBwYkS6X6ER4mHcNu71rIAcpsAFgECAa6MRJTtc1lh-fKI1UPiAGDvRI3AeJqQF8lb0v6GdOMzHEHrSJbEhCxYusjzYfvQZjU_BsfS1cflE5bB0pIygQj1UUJobUvxLpRuWLqBluO0Y6GJ9XKNGgP-qUYuFwnYI7q43todL0WhWLrwyGMmWj43JlagBG2JVTMorfGBfFVGK4OSjdeQ55F0OaGY1_7A-EirouNQ5Nv22aMjpodKvCh68K5kfKv1qe4fnf0DS6LxBzIPiBLKlLqRSNy-qNyehoxv87zG2rrztWwIkwHRapxlBKvwHl1Q1pCLxAt0-SDPlckL2xjpGZ_eJC7YXEjp0NP7nHTlVIB8BXmuKPa9UBpJHO4osOsy-Eli-ZTo-dZ2kEjVN6pa6i5OmAN-QfZdhdfO1Xj0IG4sw6sKFQgoGx9sDbJlCwQLDvfdg3iFOhKhjxIuyVoB4zxYoIVXqMRJmQPpNSooodUPlIAmOIVUWF5JBBUY54Nbz54CVMK3FRfOR5S4_7rmAtZHLQICS1e0wVD57Shncbnx5ERH_OcY4_fggKXr95K9QvWQ_Z9VzNXEdZPD2p4wx7eAVA2r3RUvkr0UxvILNJ5CC8Jt0B0IBoRz4gytqq97T3s0wLOR6PSZwvbBOnHAATwFxif-ATYnQkVwVsJAgSQvPuXfvYlfxHhw2f4Iw52Ny778vyardCgCerAFlbdvj1Plbyms1QuCt_8XdX7qbbq5RLGgPO4ILap29QPzAIYaR-GpptlkeQm75eDumVgHv06gqx6HoXHm51lMNzR7XClNpBZBlXkpfNT5zPiiFbp1n_GpoH_tnvEpycSuRMG8vwHGFzeBddcVo8n6C7BYljyYo71ZAspDIbwqhdbnjpLQTU6zlK04WyTKwFG4oMpGC9cNUBUlkjZ5YFli8LVjT5ZEvy2oANKiN4xPArw6FfC9hkprXxQOHvvgQ5vT1r74C3_iQHeNYesQ70L4o6EjK0v2tws_meh-iXY-uKYMD53nlk7tAQknqyRcj4TWOp_uCC0q3_cjdbKE-wDaZZYu4R29yfrrsouZ0sJ70hqEMoQEy5Jr0WZJB4wM1nkQHgyipOJYgTAyDryXHDuMuFujz1HKU0ehJHZHyYA0t8JwRZgSbvCELtpBeX9sdN1TwEloJamfUlv49DjdwtOe-gOxprKN7ma8SjiJMbToW4GkSMLeuhtV3YAobcuySpzww2nJ0u2te_nvTh2UiVEfrQ8ooTgDGyVGlRaUgS_GexplPk40yvsmjviz4WQ2ZTyNL0pb0ydAn6fTEc-S2STLb3tC--vJeSpn6Uz0cD6c8MlkNp7wpFfN97yUnCelGI5RopjO0jRJxvvZrJyKYp_xnprzhI-GSTIcjodjngykENNiVO7lfp9hwSUbJVgLpQfk7cC6Qy-6NR8Ok2ya9rQoUPv40cX57STH6SPMzWOMRXPwbJRo5YN_1xNU0PFz7WbbeA2_RcBQfoY0KFNa57AM-gyVMFKjf4DK9xqn5_87AF1spzn_TwAAAP__xKpb_w">