Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/dng_sdk/source/dng_safe_arithmetic.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *
3
 * Copyright (C) 2015 The Android Open Source Project
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
// Functions for safe arithmetic (guarded against overflow) on integer types.
19
20
#ifndef __dng_safe_arithmetic__
21
#define __dng_safe_arithmetic__
22
23
#include <cstddef>
24
#include <cstdint>
25
#include <limits>
26
27
#include "dng_exceptions.h"
28
29
#ifndef __has_builtin
30
#define __has_builtin(x) 0  // Compatibility with non-Clang compilers.
31
#endif
32
33
#if !defined(DNG_HAS_INT128) && defined(__SIZEOF_INT128__)
34
#define DNG_HAS_INT128
35
#endif
36
37
// If the result of adding arg1 and arg2 will fit in an int32_t (without
38
// under-/overflow), stores this result in *result and returns true. Otherwise,
39
// returns false and leaves *result unchanged.
40
bool SafeInt32Add(std::int32_t arg1, std::int32_t arg2, std::int32_t *result);
41
42
// Returns the result of adding arg1 and arg2 if it will fit in the result type
43
// (without under-/overflow). Otherwise, throws a dng_exception with error code
44
// dng_error_unknown.
45
std::int32_t SafeInt32Add(std::int32_t arg1, std::int32_t arg2);
46
std::int64_t SafeInt64Add(std::int64_t arg1, std::int64_t arg2);
47
48
// If the result of adding arg1 and arg2 will fit in a uint32_t (without
49
// wraparound), stores this result in *result and returns true. Otherwise,
50
// returns false and leaves *result unchanged.
51
bool SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2,
52
                   std::uint32_t *result);
53
54
// Returns the result of adding arg1 and arg2 if it will fit in the result type
55
// (without wraparound). Otherwise, throws a dng_exception with error code
56
// dng_error_unknown.
57
std::uint32_t SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2);
58
std::uint64_t SafeUint64Add(std::uint64_t arg1, std::uint64_t arg2);
59
60
// If the subtraction of arg2 from arg1 will not result in an int32_t under- or
61
// overflow, stores this result in *result and returns true. Otherwise,
62
// returns false and leaves *result unchanged.
63
bool SafeInt32Sub(std::int32_t arg1, std::int32_t arg2, std::int32_t *result);
64
65
// Returns the result of subtracting arg2 from arg1 if this operation will not
66
// result in an int32_t under- or overflow. Otherwise, throws a dng_exception
67
// with error code dng_error_unknown.
68
std::int32_t SafeInt32Sub(std::int32_t arg1, std::int32_t arg2);
69
70
// Returns the result of subtracting arg2 from arg1 if this operation will not
71
// result in wraparound. Otherwise, throws a dng_exception with error code
72
// dng_error_unknown.
73
std::uint32_t SafeUint32Sub(std::uint32_t arg1, std::uint32_t arg2);
74
75
// Returns the result of multiplying arg1 and arg2 if it will fit in a int32_t
76
// (without overflow). Otherwise, throws a dng_exception with error code
77
// dng_error_unknown.
78
std::int32_t SafeInt32Mult(std::int32_t arg1, std::int32_t arg2);
79
80
// If the result of multiplying arg1, ..., argn will fit in a uint32_t (without
81
// wraparound), stores this result in *result and returns true. Otherwise,
82
// returns false and leaves *result unchanged.
83
bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
84
                    std::uint32_t *result);
85
bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3,
86
                    std::uint32_t *result);
87
bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3,
88
                    std::uint32_t arg4, std::uint32_t *result);
89
90
// Returns the result of multiplying arg1, ..., argn if it will fit in a
91
// uint32_t (without wraparound). Otherwise, throws a dng_exception with error
92
// code dng_error_unknown.
93
std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2);
94
std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
95
                             std::uint32_t arg3);
96
std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
97
                             std::uint32_t arg3, std::uint32_t arg4);
98
99
// Returns the result of multiplying arg1 and arg2 if it will fit in a size_t
100
// (without overflow). Otherwise, throws a dng_exception with error code
101
// dng_error_unknown.
102
std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2);
103
104
namespace dng_internal {
105
106
// Internal function used as fallback for SafeInt64Mult() if other optimized
107
// computation is not supported. Don't call this function directly.
108
std::int64_t SafeInt64MultSlow(std::int64_t arg1, std::int64_t arg2);
109
110
// Internal function used as optimization for SafeInt64Mult() if Clang
111
// __builtin_smull_overflow is supported. Don't call this function directly.
112
#if __has_builtin(__builtin_smull_overflow)
113
0
inline std::int64_t SafeInt64MultByClang(std::int64_t arg1, std::int64_t arg2) {
114
0
  std::int64_t result;
115
0
#if (__WORDSIZE == 64) && !defined(__APPLE__)
116
0
  if (__builtin_smull_overflow(arg1, arg2, &result)) {
117
#else
118
  if (__builtin_smulll_overflow(arg1, arg2, &result)) {
119
#endif
120
0
    ThrowProgramError("Arithmetic overflow");
121
0
    abort();  // Never reached.
122
0
  }
123
0
  return result;
124
0
}
125
#endif
126
127
// Internal function used as optimization for SafeInt64Mult() if __int128 type
128
// is supported. Don't call this function directly.
129
#ifdef DNG_HAS_INT128
130
inline std::int64_t SafeInt64MultByInt128(std::int64_t arg1,
131
0
                                          std::int64_t arg2) {
132
0
  const __int128 kInt64Max =
133
0
      static_cast<__int128>(std::numeric_limits<std::int64_t>::max());
134
0
  const __int128 kInt64Min =
135
0
      static_cast<__int128>(std::numeric_limits<std::int64_t>::min());
136
0
  __int128 result = static_cast<__int128>(arg1) * static_cast<__int128>(arg2);
137
0
  if (result > kInt64Max || result < kInt64Min) {
138
0
    ThrowProgramError("Arithmetic overflow");
139
0
  }
140
0
  return static_cast<std::int64_t>(result);
141
0
}
142
#endif
143
144
}  // namespace dng_internal
145
146
// Returns the result of multiplying arg1 and arg2 if it will fit in an int64_t
147
// (without overflow). Otherwise, throws a dng_exception with error code
148
// dng_error_unknown.
149
0
inline std::int64_t SafeInt64Mult(std::int64_t arg1, std::int64_t arg2) {
150
0
#if __has_builtin(__builtin_smull_overflow)
151
0
  return dng_internal::SafeInt64MultByClang(arg1, arg2);
152
#elif defined(DNG_HAS_INT128)
153
  return dng_internal::SafeInt64MultByInt128(arg1, arg2);
154
#else
155
  return dng_internal::SafeInt64MultSlow(arg1, arg2);
156
#endif
157
0
}
158
159
// Returns the result of dividing arg1 by arg2; if the result is not an integer,
160
// rounds up to the next integer. If arg2 is zero, throws a dng_exception with
161
// error code dng_error_unknown.
162
// The function is safe against wraparound and will return the correct result
163
// for all combinations of arg1 and arg2.
164
std::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2);
165
166
// Finds the smallest integer multiple of 'multiple_of' that is greater than or
167
// equal to 'val'. If this value will fit in a uint32_t, stores it in *result
168
// and returns true. Otherwise, or if 'multiple_of' is zero, returns false and
169
// leaves *result unchanged.
170
bool RoundUpUint32ToMultiple(std::uint32_t val, std::uint32_t multiple_of,
171
                             std::uint32_t *result);
172
173
// Returns the smallest integer multiple of 'multiple_of' that is greater than
174
// or equal to 'val'. If the result will not fit in a std::uint32_t or if
175
// 'multiple_of' is zero, throws a dng_exception with error code
176
// dng_error_unknown.
177
std::uint32_t RoundUpUint32ToMultiple(std::uint32_t val,
178
                                      std::uint32_t multiple_of);
179
180
// If the uint32_t value val will fit in a int32_t, converts it to a int32_t and
181
// stores it in *result. Otherwise, returns false and leaves *result unchanged.
182
bool ConvertUint32ToInt32(std::uint32_t val, std::int32_t *result);
183
184
// Returns the result of converting val to an int32_t if it can be converted
185
// without overflow. Otherwise, throws a dng_exception with error code
186
// dng_error_unknown.
187
std::int32_t ConvertUint32ToInt32(std::uint32_t val);
188
189
// Converts a value of the unsigned integer type TSrc to the unsigned integer
190
// type TDest. If the value in 'src' cannot be converted to the type TDest
191
// without truncation, throws a dng_exception with error code dng_error_unknown.
192
//
193
// Note: Though this function is typically used where TDest is a narrower type
194
// than TSrc, it is designed to work also if TDest is wider than from TSrc or
195
// identical to TSrc. This is useful in situations where the width of the types
196
// involved can change depending on the architecture -- for example, the
197
// conversion from size_t to uint32_t may either be narrowing, identical or even
198
// widening (though the latter admittedly happens only on architectures that
199
// aren't relevant to us).
200
template <class TSrc, class TDest>
201
54.1k
static void ConvertUnsigned(TSrc src, TDest *dest) {
202
54.1k
  static_assert(std::numeric_limits<TSrc>::is_integer &&
203
54.1k
                    !std::numeric_limits<TSrc>::is_signed &&
204
54.1k
                    std::numeric_limits<TDest>::is_integer &&
205
54.1k
                    !std::numeric_limits<TDest>::is_signed,
206
54.1k
                "TSrc and TDest must be unsigned integer types");
207
208
54.1k
  const TDest converted = static_cast<TDest>(src);
209
210
  // Convert back to TSrc to check whether truncation occurred in the
211
  // conversion to TDest.
212
54.1k
  if (static_cast<TSrc>(converted) != src) {
213
0
    ThrowProgramError("Overflow in unsigned integer conversion");
214
0
  }
215
216
54.1k
  *dest = converted;
217
54.1k
}
Unexecuted instantiation: dng_read_image.cpp:void ConvertUnsigned<unsigned int, unsigned long>(unsigned int, unsigned long*)
Unexecuted instantiation: dng_read_image.cpp:void ConvertUnsigned<unsigned int, unsigned int>(unsigned int, unsigned int*)
dng_string.cpp:void ConvertUnsigned<unsigned long, unsigned int>(unsigned long, unsigned int*)
Line
Count
Source
201
54.1k
static void ConvertUnsigned(TSrc src, TDest *dest) {
202
54.1k
  static_assert(std::numeric_limits<TSrc>::is_integer &&
203
54.1k
                    !std::numeric_limits<TSrc>::is_signed &&
204
54.1k
                    std::numeric_limits<TDest>::is_integer &&
205
54.1k
                    !std::numeric_limits<TDest>::is_signed,
206
54.1k
                "TSrc and TDest must be unsigned integer types");
207
208
54.1k
  const TDest converted = static_cast<TDest>(src);
209
210
  // Convert back to TSrc to check whether truncation occurred in the
211
  // conversion to TDest.
212
54.1k
  if (static_cast<TSrc>(converted) != src) {
213
0
    ThrowProgramError("Overflow in unsigned integer conversion");
214
0
  }
215
216
54.1k
  *dest = converted;
217
54.1k
}
Unexecuted instantiation: dng_jpeg_memory_source.cpp:void ConvertUnsigned<unsigned long, unsigned long>(unsigned long, unsigned long*)
218
219
// Returns the result of converting val to the result type using truncation if
220
// val is in range of the result type values. Otherwise, throws a dng_exception
221
// with error code dng_error_unknown.
222
std::int32_t ConvertDoubleToInt32(double val);
223
std::uint32_t ConvertDoubleToUint32(double val);
224
225
// Returns the result of converting val to float. If val is outside of
226
// [-FLT_MAX, FLT_MAX], -infinity and infinity is returned respectively. NaN is
227
// returned as NaN.
228
float ConvertDoubleToFloat(double val);
229
230
#endif  // __dng_safe_arithmetic__