diff options
-rw-r--r-- | include/linux/overflow.h | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/include/linux/overflow.h b/include/linux/overflow.h index 8712ff70995f..40b48e2133cb 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h | |||
@@ -202,6 +202,37 @@ | |||
202 | 202 | ||
203 | #endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ | 203 | #endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ |
204 | 204 | ||
205 | /** check_shl_overflow() - Calculate a left-shifted value and check overflow | ||
206 | * | ||
207 | * @a: Value to be shifted | ||
208 | * @s: How many bits left to shift | ||
209 | * @d: Pointer to where to store the result | ||
210 | * | ||
211 | * Computes *@d = (@a << @s) | ||
212 | * | ||
213 | * Returns true if '*d' cannot hold the result or when 'a << s' doesn't | ||
214 | * make sense. Example conditions: | ||
215 | * - 'a << s' causes bits to be lost when stored in *d. | ||
216 | * - 's' is garbage (e.g. negative) or so large that the result of | ||
217 | * 'a << s' is guaranteed to be 0. | ||
218 | * - 'a' is negative. | ||
219 | * - 'a << s' sets the sign bit, if any, in '*d'. | ||
220 | * | ||
221 | * '*d' will hold the results of the attempted shift, but is not | ||
222 | * considered "safe for use" if false is returned. | ||
223 | */ | ||
224 | #define check_shl_overflow(a, s, d) ({ \ | ||
225 | typeof(a) _a = a; \ | ||
226 | typeof(s) _s = s; \ | ||
227 | typeof(d) _d = d; \ | ||
228 | u64 _a_full = _a; \ | ||
229 | unsigned int _to_shift = \ | ||
230 | _s >= 0 && _s < 8 * sizeof(*d) ? _s : 0; \ | ||
231 | *_d = (_a_full << _to_shift); \ | ||
232 | (_to_shift != _s || *_d < 0 || _a < 0 || \ | ||
233 | (*_d >> _to_shift) != _a); \ | ||
234 | }) | ||
235 | |||
205 | /** | 236 | /** |
206 | * array_size() - Calculate size of 2-dimensional array. | 237 | * array_size() - Calculate size of 2-dimensional array. |
207 | * | 238 | * |