17
17
#include < __functional/hash.h>
18
18
#include < __functional/operations.h>
19
19
#include < __memory/allocator_traits.h> // __pointer
20
+ #include < __memory/array_cookie.h>
20
21
#include < __memory/auto_ptr.h>
21
22
#include < __memory/compressed_pair.h>
23
+ #include < __memory/pointer_traits.h>
22
24
#include < __type_traits/add_lvalue_reference.h>
23
25
#include < __type_traits/common_type.h>
24
26
#include < __type_traits/conditional.h>
40
42
#include < __utility/declval.h>
41
43
#include < __utility/forward.h>
42
44
#include < __utility/move.h>
45
+ #include < __utility/private_constructor_tag.h>
46
+ #include < climits>
43
47
#include < cstddef>
44
48
45
49
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -283,6 +287,85 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
283
287
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap (unique_ptr& __u) _NOEXCEPT { __ptr_.swap (__u.__ptr_ ); }
284
288
};
285
289
290
+ // Bounds checking in unique_ptr<T[]>
291
+ // ==================================
292
+ //
293
+ // We provide some helper classes that allow bounds checking when accessing a unique_ptr<T[]>.
294
+ // There are a few cases where bounds checking can be implemented:
295
+ //
296
+ // 1. When an array cookie (see [1]) exists at the beginning of the array allocation, we are
297
+ // able to reuse that cookie to extract the size of the array and perform bounds checking.
298
+ // An array cookie is a size inserted at the beginning of the allocation by the compiler.
299
+ // That size is inserted implicitly when doing `new T[n]` in some cases, and its purpose
300
+ // is to allow the runtime to destroy the `n` array elements when doing `delete array`.
301
+ // When we are able to use array cookies, we reuse information already available in the
302
+ // current runtime, so bounds checking does not require changing libc++'s ABI.
303
+ //
304
+ // 2. When the "bounded unique_ptr" ABI configuration (controlled by `_LIBCPP_ABI_BOUNDED_UNIQUE_PTR`)
305
+ // is enabled, we store the size of the allocation (when it is known) so we can check it when
306
+ // indexing into the `unique_ptr`. That changes the layout of `std::unique_ptr<T[]>`, which is
307
+ // an ABI break from the default configuration.
308
+ //
309
+ // Note that even under this ABI configuration, we can't always know the size of the unique_ptr.
310
+ // Indeed, the size of the allocation can only be known when the unique_ptr is created via
311
+ // make_unique or a similar API. For example, it can't be known when constructed from an arbitrary
312
+ // pointer, in which case we are not able to check the bounds on access:
313
+ //
314
+ // unique_ptr<T[], MyDeleter> ptr(new T[3]);
315
+ //
316
+ // When we don't know the size of the allocation via the API used to create the unique_ptr, we
317
+ // try to fall back to using an array cookie when available.
318
+ //
319
+ // Finally, note that when this ABI configuration is enabled, we have no choice but to always
320
+ // make space for a size to be stored in the unique_ptr. Indeed, while we might want to avoid
321
+ // storing the size when an array cookie is available, knowing whether an array cookie is available
322
+ // requires the type stored in the unique_ptr to be complete, while unique_ptr can normally
323
+ // accommodate incomplete types.
324
+ //
325
+ // (1) Implementation where we rely on the array cookie to know the size of the allocation, if
326
+ // an array cookie exists.
327
+ struct __unique_ptr_array_bounds_stateless {
328
+ _LIBCPP_HIDE_FROM_ABI __unique_ptr_array_bounds_stateless () = default;
329
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __unique_ptr_array_bounds_stateless (size_t ) {}
330
+
331
+ template <class _Tp , __enable_if_t <__has_array_cookie<_Tp>::value, int > = 0 >
332
+ _LIBCPP_HIDE_FROM_ABI bool __in_bounds (_Tp* __ptr, size_t __index) const {
333
+ size_t __cookie = std::__get_array_cookie (__ptr);
334
+ return __index < __cookie;
335
+ }
336
+
337
+ template <class _Tp , __enable_if_t <!__has_array_cookie<_Tp>::value, int > = 0 >
338
+ _LIBCPP_HIDE_FROM_ABI bool __in_bounds (_Tp*, size_t ) const {
339
+ return true ; // If we don't have an array cookie, we assume the access is in-bounds
340
+ }
341
+ };
342
+
343
+ // (2) Implementation where we store the size in the class whenever we have it.
344
+ //
345
+ // Semantically, we'd need to store the size as an optional<size_t>. However, since that
346
+ // is really heavy weight, we instead store a size_t and use SIZE_MAX as a magic value
347
+ // meaning that we don't know the size.
348
+ struct __unique_ptr_array_bounds_stored {
349
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __unique_ptr_array_bounds_stored () : __size_(SIZE_MAX) {}
350
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __unique_ptr_array_bounds_stored (size_t __size) : __size_(__size) {}
351
+
352
+ // Use the array cookie if there's one
353
+ template <class _Tp , __enable_if_t <__has_array_cookie<_Tp>::value, int > = 0 >
354
+ _LIBCPP_HIDE_FROM_ABI bool __in_bounds (_Tp* __ptr, size_t __index) const {
355
+ size_t __cookie = std::__get_array_cookie (__ptr);
356
+ return __index < __cookie;
357
+ }
358
+
359
+ // Otherwise, fall back on the stored size (if any)
360
+ template <class _Tp , __enable_if_t <!__has_array_cookie<_Tp>::value, int > = 0 >
361
+ _LIBCPP_HIDE_FROM_ABI bool __in_bounds (_Tp*, size_t __index) const {
362
+ return __index < __size_;
363
+ }
364
+
365
+ private:
366
+ size_t __size_;
367
+ };
368
+
286
369
template <class _Tp , class _Dp >
287
370
class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> {
288
371
public:
@@ -291,8 +374,9 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
291
374
typedef typename __pointer<_Tp, deleter_type>::type pointer;
292
375
293
376
// A unique_ptr contains the following members which may be trivially relocatable:
294
- // - pointer : this may be trivially relocatable, so it's checked
377
+ // - pointer: this may be trivially relocatable, so it's checked
295
378
// - deleter_type: this may be trivially relocatable, so it's checked
379
+ // - (optionally) size: this is trivially relocatable
296
380
//
297
381
// This unique_ptr implementation only contains a pointer to the unique object and a deleter, so there are no
298
382
// references to itself. This means that the entire structure is trivially relocatable if its members are.
@@ -303,6 +387,15 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
303
387
304
388
private:
305
389
__compressed_pair<pointer, deleter_type> __ptr_;
390
+ #ifdef _LIBCPP_ABI_BOUNDED_UNIQUE_PTR
391
+ using _BoundsChecker = __unique_ptr_array_bounds_stored;
392
+ #else
393
+ using _BoundsChecker = __unique_ptr_array_bounds_stateless;
394
+ #endif
395
+ _LIBCPP_NO_UNIQUE_ADDRESS _BoundsChecker __checker_;
396
+
397
+ template <class , class >
398
+ friend class unique_ptr ; // access __checker_ in other unique_ptrs
306
399
307
400
template <class _From >
308
401
struct _CheckArrayPointerConversion : is_same<_From, pointer> {};
@@ -364,6 +457,12 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
364
457
_LIBCPP_HIDE_FROM_ABI
365
458
_LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr (_Pp __p) _NOEXCEPT : __ptr_(__p, __value_init_tag()) {}
366
459
460
+ // Private constructor used by make_unique & friends to pass the size that was allocated
461
+ template <class _Tag , class _Ptr , __enable_if_t <is_same<_Tag, __private_constructor_tag>::value, int > = 0 >
462
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr (_Tag, _Ptr __ptr, size_t __size) _NOEXCEPT
463
+ : __ptr_(__ptr, __value_init_tag()),
464
+ __checker_(__size) {}
465
+
367
466
template <class _Pp ,
368
467
bool _Dummy = true ,
369
468
class = _EnableIfDeleterConstructible<_LValRefType<_Dummy> >,
@@ -397,11 +496,13 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
397
496
_LIBCPP_HIDE_FROM_ABI unique_ptr (_Pp __p, _BadRValRefType<_Dummy> __d) = delete;
398
497
399
498
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr (unique_ptr&& __u) _NOEXCEPT
400
- : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())) {}
499
+ : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())),
500
+ __checker_(std::move(__u.__checker_)) {}
401
501
402
502
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator =(unique_ptr&& __u) _NOEXCEPT {
403
503
reset (__u.release ());
404
504
__ptr_.second () = std::forward<deleter_type>(__u.get_deleter ());
505
+ __checker_ = std::move (__u.__checker_ );
405
506
return *this ;
406
507
}
407
508
@@ -410,7 +511,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
410
511
class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>,
411
512
class = _EnableIfDeleterConvertible<_Ep> >
412
513
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr (unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT
413
- : __ptr_(__u.release(), std::forward<_Ep>(__u.get_deleter())) {}
514
+ : __ptr_(__u.release(), std::forward<_Ep>(__u.get_deleter())),
515
+ __checker_(std::move(__u.__checker_)) {}
414
516
415
517
template <class _Up ,
416
518
class _Ep ,
@@ -419,6 +521,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
419
521
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator =(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT {
420
522
reset (__u.release ());
421
523
__ptr_.second () = std::forward<_Ep>(__u.get_deleter ());
524
+ __checker_ = std::move (__u.__checker_ );
422
525
return *this ;
423
526
}
424
527
@@ -436,6 +539,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
436
539
}
437
540
438
541
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t <_Tp> operator [](size_t __i) const {
542
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS (__checker_.__in_bounds (std::__to_address (__ptr_.first ()), __i),
543
+ " unique_ptr<T[]>::operator[](index): index out of range" );
439
544
return __ptr_.first ()[__i];
440
545
}
441
546
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get () const _NOEXCEPT { return __ptr_.first (); }
@@ -452,25 +557,31 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
452
557
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer release () _NOEXCEPT {
453
558
pointer __t = __ptr_.first ();
454
559
__ptr_.first () = pointer ();
560
+ __checker_ = _BoundsChecker ();
455
561
return __t ;
456
562
}
457
563
458
564
template <class _Pp , __enable_if_t <_CheckArrayPointerConversion<_Pp>::value, int > = 0 >
459
565
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset (_Pp __p) _NOEXCEPT {
460
566
pointer __tmp = __ptr_.first ();
461
567
__ptr_.first () = __p;
568
+ __checker_ = _BoundsChecker ();
462
569
if (__tmp)
463
570
__ptr_.second ()(__tmp);
464
571
}
465
572
466
573
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset (nullptr_t = nullptr ) _NOEXCEPT {
467
574
pointer __tmp = __ptr_.first ();
468
575
__ptr_.first () = nullptr ;
576
+ __checker_ = _BoundsChecker ();
469
577
if (__tmp)
470
578
__ptr_.second ()(__tmp);
471
579
}
472
580
473
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap (unique_ptr& __u) _NOEXCEPT { __ptr_.swap (__u.__ptr_ ); }
581
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap (unique_ptr& __u) _NOEXCEPT {
582
+ __ptr_.swap (__u.__ptr_ );
583
+ std::swap (__checker_, __u.__checker_ );
584
+ }
474
585
};
475
586
476
587
template <class _Tp , class _Dp , __enable_if_t <__is_swappable_v<_Dp>, int > = 0 >
@@ -626,7 +737,7 @@ template <class _Tp>
626
737
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
627
738
make_unique (size_t __n) {
628
739
typedef __remove_extent_t <_Tp> _Up;
629
- return unique_ptr<_Tp>(new _Up[__n]());
740
+ return unique_ptr<_Tp>(__private_constructor_tag (), new _Up[__n](), __n );
630
741
}
631
742
632
743
template <class _Tp , class ... _Args>
@@ -645,7 +756,7 @@ make_unique_for_overwrite() {
645
756
template <class _Tp >
646
757
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
647
758
make_unique_for_overwrite (size_t __n) {
648
- return unique_ptr<_Tp>(new __remove_extent_t <_Tp>[__n]);
759
+ return unique_ptr<_Tp>(__private_constructor_tag (), new __remove_extent_t <_Tp>[__n], __n );
649
760
}
650
761
651
762
template <class _Tp , class ... _Args>
0 commit comments