xref: /xnu-12377.81.4/libkern/os/cxx_safe_buffers.h (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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