1 /* * Copyright (c) 2018 Apple Inc. All rights reserved.
2 *
3 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
4 *
5 * This file contains Original Code and/or Modifications of Original Code
6 * as defined in and that are subject to the Apple Public Source License
7 * Version 2.0 (the 'License'). You may not use this file except in
8 * compliance with the License. The rights granted to you under the License
9 * may not be used to create, or enable the creation or redistribution of,
10 * unlawful or unlicensed copies of an Apple operating system, or to
11 * circumvent, violate, or enable the circumvention or violation of, any
12 * terms of an Apple operating system software license agreement.
13 *
14 * Please obtain a copy of the License at
15 * http://www.opensource.apple.com/apsl/ and read it before using this file.
16 *
17 * The Original Code and all software distributed under the License are
18 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
20 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
22 * Please see the License for the specific language governing rights and
23 * limitations under the License.
24 *
25 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
26 */
27
28
29 #ifndef _OS_CXX_SAFE_BUFFERS_H
30 #define _OS_CXX_SAFE_BUFFERS_H
31
32 #ifdef KERNEL_PRIVATE
33 #include <kern/kalloc.h>
34 #endif
35
36 #if (defined(__has_include) && __has_include(<span>) && __has_include(<iterator>) && __has_include(<type_traits>))
37 #include <iterator>
38 #include <span>
39 #include <type_traits>
40
41 namespace os {
42 #pragma clang unsafe_buffer_usage begin
43 /* The `unsafe_forge_span` functions are for suppressing false
44 * positive `-Wunsafe-buffer-usage-in-container` warnings on
45 * uses of the two-parameter `std::span` constructors.
46 *
47 * For a `std::span(ptr, size)` call that raises a false alarm, one
48 * can suppress the warning by changing the call to
49 * `unsafe_forge_span(ptr, size)`.
50 *
51 * Please consider the C++ Safe Buffers Programming Model and
52 * Adoption Tooling Guide as a reference to identify false positives
53 * and do not use the functions in non-applicable cases.
54 */
55 template<std::contiguous_iterator It>
56 std::span<std::remove_reference_t<std::iter_reference_t<It> > >
unsafe_forge_span(It data,typename std::span<std::remove_reference_t<std::iter_reference_t<It>>>::size_type size)57 unsafe_forge_span(It data, typename std::span<std::remove_reference_t<std::iter_reference_t<It> > >::size_type size)
58 {
59 return std::span<std::remove_reference_t<std::iter_reference_t<It> > >{data, size};
60 }
61
62 template<std::contiguous_iterator It, std::sized_sentinel_for<It> End>
63 std::span<std::remove_reference_t<std::iter_reference_t<It> > >
unsafe_forge_span(It begin,End end)64 unsafe_forge_span(It begin, End end)
65 {
66 return std::span<std::remove_reference_t<std::iter_reference_t<It> > >{begin, end};
67 }
68
69 template<typename T, std::size_t N>
70 std::span<T, N>
unsafe_forge_span(T * data)71 unsafe_forge_span(T *data)
72 {
73 return std::span<T, N>{data, N};
74 }
75
76 template<
77 typename Dst,
78 typename Src,
79 std::size_t Count
80 #ifdef KERNEL_PRIVATE
81 , typename = std::enable_if_t<KALLOC_TYPE_IS_DATA_ONLY(Src) && KALLOC_TYPE_IS_DATA_ONLY(Dst)>
82 #endif
83 >
84 std::span<Dst, Count == std::dynamic_extent
85 ? std::dynamic_extent
86 : (Count * sizeof(Src)) / sizeof(Dst)>
reinterpret_span_cast(std::span<Src,Count> src)87 reinterpret_span_cast( std::span<Src, Count> src )
88 {
89 if constexpr (std::is_same_v<Dst, std::byte>) {
90 return std::as_writable_bytes(src);
91 } else {
92 if constexpr (std::is_same_v<Dst, const std::byte>) {
93 return std::as_bytes(src);
94 }
95 }
96
97 if constexpr (Count == std::dynamic_extent) {
98 if constexpr ((sizeof(Src) < sizeof(Dst)) || (sizeof(Src) % sizeof(Dst) != 0)) {
99 if (__builtin_expect(((src.size() * sizeof(Src)) % sizeof(Dst) != 0), 0)) {
100 #ifdef KERNEL_PRIVATE
101 ml_fatal_trap(0x0800);
102 #else
103 __builtin_verbose_trap("safe-buffers", "reinterpret_span_cast: Conversion between incompatible span sizes");
104 #endif
105 }
106 }
107 } else {
108 static_assert((Count * sizeof(Src)) % sizeof(Dst) == 0,
109 "reinterpret_span_cast: Conversion between incompatible span sizes" );
110 }
111
112 using ReturnType = std::span<Dst, Count == std::dynamic_extent
113 ? std::dynamic_extent
114 : (Count * sizeof(Src)) / sizeof(Dst)>;
115
116 return ReturnType {
117 reinterpret_cast<Dst *>(src.data()),
118 (src.size() * sizeof(Src)) / sizeof(Dst)
119 };
120 }
121
122 // We keep old function names below for better transitions in Safe
123 // Buffer adoption. These names will exist in the header for a while
124 // before being marked as "deprecated".
125 namespace span {
126 template<std::contiguous_iterator It>
127 std::span<std::remove_reference_t<std::iter_reference_t<It> > >
__unsafe_forge_span(It data,typename std::span<std::remove_reference_t<std::iter_reference_t<It>>>::size_type size)128 __unsafe_forge_span(It data, typename std::span<std::remove_reference_t<std::iter_reference_t<It> > >::size_type size)
129 {
130 return std::span<std::remove_reference_t<std::iter_reference_t<It> > >{data, size};
131 }
132
133 template<std::contiguous_iterator It, std::sized_sentinel_for<It> End>
134 std::span<std::remove_reference_t<std::iter_reference_t<It> > >
__unsafe_forge_span(It begin,End end)135 __unsafe_forge_span(It begin, End end)
136 {
137 return std::span<std::remove_reference_t<std::iter_reference_t<It> > >{begin, end};
138 }
139 } // namespace span
140 #pragma clang unsafe_buffer_usage end
141 } // namespace os
142 #endif /* (defined(__has_include) && __has_include(<span>) && __has_include(<iterator>)) */
143 #endif /* _OS_CXX_SAFE_BUFFERS_H */
144