40
40
#include < __utility/declval.h>
41
41
#include < __utility/forward.h>
42
42
#include < __utility/move.h>
43
+ #include < __utility/private_constructor_tag.h>
43
44
#include < cstddef>
44
45
45
46
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -283,6 +284,78 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
283
284
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap (unique_ptr& __u) _NOEXCEPT { __ptr_.swap (__u.__ptr_ ); }
284
285
};
285
286
287
+ // These classes are used to implement bounds checking for unique_ptr<T[]>.
288
+ //
289
+ // Under the "bounded unique_ptr" ABI, we store the size of the allocation when it is known
290
+ // so that we can check it when indexing into the unique_ptr later on. The size of the
291
+ // allocation can be known when unique_ptr is created via make_unique or a similar API,
292
+ // however it can't be known when constructed from an arbitrary pointer, e.g.
293
+ //
294
+ // unique_ptr<T[], MyDeleter> ptr(new T[3]);
295
+ //
296
+ // In that case, we don't know the size of the allocation from within the unique_ptr.
297
+ // Semantically, we'd need to store `optional<size_t>`. However, since that is really
298
+ // heavy weight, we instead store a size_t and use 0 as a magic value meaning that we
299
+ // don't know the size. This means that we can't catch OOB accesses inside a unique_ptr
300
+ // with a 0-sized allocation, however since this is a degenerate case, it doesn't matter
301
+ // in practice.
302
+ //
303
+ // As a nice simplification, we don't need to store the size inside the unique_ptr when
304
+ // the deleter is std::default_delete<T[]>. Indeed, the compiler already inserts the size
305
+ // of the array before the allocation (this is called an array cookie) since that is required
306
+ // for the language runtime to implement operator delete[]. In that (very common) case, we
307
+ // use the array cookie and avoid storing the size, which makes it possible to perform bounds
308
+ // checking without any ABI change.
309
+
310
+ // Implementation where we don't store any bounds information and we don't attempt to perform
311
+ // any bounds checking.
312
+ template <class _Pointer >
313
+ struct __unique_ptr_array_bounds_none {
314
+ _LIBCPP_HIDE_FROM_ABI __unique_ptr_array_bounds_none () = default;
315
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __unique_ptr_array_bounds_none (size_t ) {}
316
+
317
+ // Pretend the index is always in-bounds.
318
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __in_bounds (_Pointer, size_t ) const { return true ; }
319
+ };
320
+
321
+ // Implementation where we store the size information in the class whenever we have it.
322
+ // The special value `0` is used to represent that we don't have any bounds information.
323
+ template <class _Pointer >
324
+ struct __unique_ptr_array_bounds_local {
325
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __unique_ptr_array_bounds_local () : __size_(0 ) {}
326
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __unique_ptr_array_bounds_local (size_t __size) : __size_(__size) {}
327
+
328
+ // Check against the size we stored (if any)
329
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __in_bounds (_Pointer, size_t __index) const {
330
+ return __size_ == 0 || __index < __size_;
331
+ }
332
+
333
+ private:
334
+ size_t __size_;
335
+ };
336
+
337
+ // Implementation where we rely on the array cookie to know the size of the allocation.
338
+ // When the deleter is std::default_delete, we never need to store the size inside the unique_ptr
339
+ // because the compiler already inserts an array cookie before the array allocation (since that is
340
+ // required for operator delete[]).
341
+ template <class _Pointer >
342
+ struct __unique_ptr_array_bounds_cookie {
343
+ _LIBCPP_HIDE_FROM_ABI __unique_ptr_array_bounds_cookie () = default;
344
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __unique_ptr_array_bounds_cookie (size_t ) {}
345
+
346
+ // Check against the array cookie
347
+ _LIBCPP_HIDE_FROM_ABI bool __in_bounds (_Pointer __ptr, size_t __index) const {
348
+ size_t * __cookie = reinterpret_cast <size_t *>(std::__to_address (__ptr)) - 1 ; // TODO: Use a builtin instead?
349
+ return __index < *__cookie;
350
+ }
351
+ };
352
+
353
+ template <class _Deleter >
354
+ inline constexpr bool __has_array_cookie = false ;
355
+
356
+ template <class _Tp >
357
+ inline constexpr bool __has_array_cookie<default_delete<_Tp[]>> = true ;
358
+
286
359
template <class _Tp , class _Dp >
287
360
class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> {
288
361
public:
@@ -291,8 +364,9 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
291
364
typedef typename __pointer<_Tp, deleter_type>::type pointer;
292
365
293
366
// A unique_ptr contains the following members which may be trivially relocatable:
294
- // - pointer : this may be trivially relocatable, so it's checked
367
+ // - pointer: this may be trivially relocatable, so it's checked
295
368
// - deleter_type: this may be trivially relocatable, so it's checked
369
+ // - (optionally) size: this is trivially relocatable
296
370
//
297
371
// This unique_ptr implementation only contains a pointer to the unique object and a deleter, so there are no
298
372
// references to itself. This means that the entire structure is trivially relocatable if its members are.
@@ -303,6 +377,16 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
303
377
304
378
private:
305
379
__compressed_pair<pointer, deleter_type> __ptr_;
380
+ using _BoundsChecker =
381
+ __conditional_t <__has_array_cookie<deleter_type>,
382
+ __unique_ptr_array_bounds_cookie<pointer>,
383
+ #ifdef _LIBCPP_ABI_BOUNDED_UNIQUE_PTR
384
+ __unique_ptr_array_bounds_local<pointer>
385
+ #else
386
+ __unique_ptr_array_bounds_none<pointer>
387
+ #endif
388
+ >;
389
+ _LIBCPP_NO_UNIQUE_ADDRESS _BoundsChecker __checker_;
306
390
307
391
template <class _From >
308
392
struct _CheckArrayPointerConversion : is_same<_From, pointer> {};
@@ -364,6 +448,12 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
364
448
_LIBCPP_HIDE_FROM_ABI
365
449
_LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr (_Pp __p) _NOEXCEPT : __ptr_(__p, __value_init_tag()) {}
366
450
451
+ // Private constructor used by make_unique & friends to pass the size that was allocated
452
+ template <class _Tag , class _Ptr , __enable_if_t <is_same<_Tag, __private_constructor_tag>::value, int > = 0 >
453
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr (_Tag, _Ptr __ptr, size_t __size) _NOEXCEPT
454
+ : __ptr_(__ptr, __value_init_tag()),
455
+ __checker_(__size) {}
456
+
367
457
template <class _Pp ,
368
458
bool _Dummy = true ,
369
459
class = _EnableIfDeleterConstructible<_LValRefType<_Dummy> >,
@@ -397,11 +487,13 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
397
487
_LIBCPP_HIDE_FROM_ABI unique_ptr (_Pp __p, _BadRValRefType<_Dummy> __d) = delete;
398
488
399
489
_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())) {}
490
+ : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())),
491
+ __checker_(std::move(__u.__checker_)) {}
401
492
402
493
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator =(unique_ptr&& __u) _NOEXCEPT {
403
494
reset (__u.release ());
404
495
__ptr_.second () = std::forward<deleter_type>(__u.get_deleter ());
496
+ __checker_ = std::move (__u.__checker_ );
405
497
return *this ;
406
498
}
407
499
@@ -410,7 +502,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
410
502
class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>,
411
503
class = _EnableIfDeleterConvertible<_Ep> >
412
504
_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())) {}
505
+ : __ptr_(__u.release(), std::forward<_Ep>(__u.get_deleter())),
506
+ __checker_(std::move(__u.__checker_)) {}
414
507
415
508
template <class _Up ,
416
509
class _Ep ,
@@ -419,6 +512,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
419
512
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator =(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT {
420
513
reset (__u.release ());
421
514
__ptr_.second () = std::forward<_Ep>(__u.get_deleter ());
515
+ __checker_ = std::move (__u.__checker_ );
422
516
return *this ;
423
517
}
424
518
@@ -436,6 +530,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
436
530
}
437
531
438
532
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t <_Tp> operator [](size_t __i) const {
533
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS (
534
+ __checker_.__in_bounds (__ptr_.first (), __i), " unique_ptr<T[]>::operator[](index): index out of range" );
439
535
return __ptr_.first ()[__i];
440
536
}
441
537
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get () const _NOEXCEPT { return __ptr_.first (); }
@@ -452,25 +548,31 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
452
548
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer release () _NOEXCEPT {
453
549
pointer __t = __ptr_.first ();
454
550
__ptr_.first () = pointer ();
551
+ __checker_ = _BoundsChecker ();
455
552
return __t ;
456
553
}
457
554
458
555
template <class _Pp , __enable_if_t <_CheckArrayPointerConversion<_Pp>::value, int > = 0 >
459
556
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset (_Pp __p) _NOEXCEPT {
460
557
pointer __tmp = __ptr_.first ();
461
558
__ptr_.first () = __p;
559
+ __checker_ = _BoundsChecker ();
462
560
if (__tmp)
463
561
__ptr_.second ()(__tmp);
464
562
}
465
563
466
564
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset (nullptr_t = nullptr ) _NOEXCEPT {
467
565
pointer __tmp = __ptr_.first ();
468
566
__ptr_.first () = nullptr ;
567
+ __checker_ = _BoundsChecker ();
469
568
if (__tmp)
470
569
__ptr_.second ()(__tmp);
471
570
}
472
571
473
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap (unique_ptr& __u) _NOEXCEPT { __ptr_.swap (__u.__ptr_ ); }
572
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap (unique_ptr& __u) _NOEXCEPT {
573
+ __ptr_.swap (__u.__ptr_ );
574
+ std::swap (__checker_, __u.__checker_ );
575
+ }
474
576
};
475
577
476
578
template <class _Tp , class _Dp , __enable_if_t <__is_swappable_v<_Dp>, int > = 0 >
@@ -626,7 +728,7 @@ template <class _Tp>
626
728
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
627
729
make_unique (size_t __n) {
628
730
typedef __remove_extent_t <_Tp> _Up;
629
- return unique_ptr<_Tp>(new _Up[__n]());
731
+ return unique_ptr<_Tp>(__private_constructor_tag (), new _Up[__n](), __n );
630
732
}
631
733
632
734
template <class _Tp , class ... _Args>
@@ -645,7 +747,7 @@ make_unique_for_overwrite() {
645
747
template <class _Tp >
646
748
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
647
749
make_unique_for_overwrite (size_t __n) {
648
- return unique_ptr<_Tp>(new __remove_extent_t <_Tp>[__n]);
750
+ return unique_ptr<_Tp>(__private_constructor_tag (), new __remove_extent_t <_Tp>[__n], __n );
649
751
}
650
752
651
753
template <class _Tp , class ... _Args>
0 commit comments