700 lines
24 KiB
C
700 lines
24 KiB
C
/* safe_iop
|
|
* License:: released in to the public domain
|
|
* Author:: Will Drewry <redpig@dataspill.org>
|
|
* Copyright 2007,2008 redpig@dataspill.org
|
|
* Some portions copyright The Android Open Source Project
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
|
* OF ANY KIND, either express or implied.
|
|
*
|
|
* To Do:
|
|
* - Add varargs style interface for safe_<op>()
|
|
* - Add support for safe conversion
|
|
* - Add additional sizes to safe_iopf (currently 32-bit only)
|
|
* (this will make use of the safe conversion above)
|
|
* - Add left shift support
|
|
* - Add more test cases for interfaces (op_mixed)
|
|
* - Add more tests for edge cases I've missed? and for thoroughness
|
|
*
|
|
* History:
|
|
* = 0.3
|
|
* - solidified code into a smaller number of macros and functions
|
|
* - added typeless functions using gcc magic (typeof)
|
|
* - deprecrated old interfaces (-DSAFE_IOP_COMPAT)
|
|
* - discover size maximums automagically
|
|
* - separated test cases for easier understanding
|
|
* - significantly expanded test cases
|
|
* - derive type maximums and minimums internally (checked in testing)
|
|
* = 0.2
|
|
* - Removed dependence on twos complement arithmetic to allow macro-ized
|
|
* definitions
|
|
* - Added (s)size_t support
|
|
* - Added (u)int8,16,64 support
|
|
* - Added portable inlining
|
|
* - Added support for NULL result pointers
|
|
* - Added support for header-only use (safe_iop.c only needed for safe_iopf)
|
|
* = 0.1
|
|
* - Initial release
|
|
*
|
|
* Contributors & thanks:
|
|
* - peter@valchev.net for his review, comments, and enthusiasm
|
|
* - thanks to Google for contributing some time
|
|
*/
|
|
|
|
/* This library supplies a set of standard functions for performing and
|
|
* checking safe integer operations. The code is based on examples from
|
|
* https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
|
|
*
|
|
* Inline functions are available for specific operations. If the result
|
|
* pointer is NULL, the function will still return 1 or 0 if it would
|
|
* or would not overflow. If multiple operations need to be performed,
|
|
* safe_iopf provides a format-string driven model, but it does not yet support
|
|
* non-32 bit operations
|
|
*
|
|
* NOTE: This code assumes int32_t to be signed.
|
|
*/
|
|
#ifndef _SAFE_IOP_H
|
|
#define _SAFE_IOP_H
|
|
#include <limits.h> /* for CHAR_BIT */
|
|
#include <assert.h> /* for type enforcement */
|
|
|
|
typedef enum { SAFE_IOP_TYPE_S32 = 1,
|
|
SAFE_IOP_TYPE_U32,
|
|
SAFE_IOP_TYPE_DEFAULT = SAFE_IOP_TYPE_S32,
|
|
} safe_type_t;
|
|
|
|
#define SAFE_IOP_TYPE_PREFIXES "us"
|
|
|
|
/* use a nice prefix :) */
|
|
#define __sio(x) OPAQUE_SAFE_IOP_PREFIX_ ## x
|
|
#define OPAQUE_SAFE_IOP_PREFIX_var(x) __sio(VARIABLE_ ## x)
|
|
#define OPAQUE_SAFE_IOP_PREFIX_m(x) __sio(MACRO_ ## x)
|
|
|
|
|
|
/* A recursive macro which safely multiplies the given type together.
|
|
* _ptr may be NULL.
|
|
* mixed types or mixed sizes will unconditionally return 0;
|
|
*/
|
|
#define OPAQUE_SAFE_IOP_PREFIX_MACRO_smax(_a) \
|
|
((typeof(_a))(~((typeof(_a)) 1 << ((sizeof(typeof(_a)) * CHAR_BIT) - 1))))
|
|
#define OPAQUE_SAFE_IOP_PREFIX_MACRO_smin(_a) \
|
|
((typeof(_a))(-__sio(m)(smax)(_a) - 1))
|
|
#define OPAQUE_SAFE_IOP_PREFIX_MACRO_umax(_a) ((typeof(_a))(~((typeof(_a)) 0)))
|
|
|
|
#define OPAQUE_SAFE_IOP_PREFIX_MACRO_type_enforce(__A, __B) \
|
|
((((__sio(m)(smin)(__A) <= ((typeof(__A))0)) && \
|
|
(__sio(m)(smin)(__B) <= ((typeof(__B))0))) || \
|
|
(((__sio(m)(smin)(__A) > ((typeof(__A))0))) && \
|
|
(__sio(m)(smin)(__B) > ((typeof(__B))0)))) && \
|
|
(sizeof(typeof(__A)) == sizeof(typeof(__B))))
|
|
|
|
|
|
/* We use a non-void wrapper for assert(). This allows us to factor it away on
|
|
* -DNDEBUG but still have conditionals test the result (and optionally return
|
|
* false).
|
|
*/
|
|
#if defined(NDEBUG)
|
|
# define OPAQUE_SAFE_IOP_PREFIX_MACRO_assert(x) (x)
|
|
#else
|
|
# define OPAQUE_SAFE_IOP_PREFIX_MACRO_assert(x) ({ assert(x); 1; })
|
|
#endif
|
|
|
|
|
|
/* Primary interface macros */
|
|
/* type checking is compiled out if NDEBUG supplied. */
|
|
#define safe_add(_ptr, __a, __b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
typeof(__a) __sio(var)(_a) = (__a); \
|
|
typeof(__b) __sio(var)(_b) = (__b); \
|
|
typeof(_ptr) __sio(var)(p) = (_ptr); \
|
|
if (__sio(m)(assert)(__sio(m)(type_enforce)(__sio(var)(_a), \
|
|
__sio(var)(_b)))) { \
|
|
if (__sio(m)(smin)(__sio(var)(_a)) <= ((typeof(__sio(var)(_a)))0)) { \
|
|
__sio(var)(ok) = safe_sadd(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} else { \
|
|
__sio(var)(ok) = safe_uadd(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_add3(_ptr, _A, _B, _C) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_add(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_add((_ptr), __sio(var)(r), __sio(var)(c))); })
|
|
|
|
#define safe_add4(_ptr, _A, _B, _C, _D) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_add(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_add(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_add((_ptr), __sio(var)(r), (__sio(var)(d)))); })
|
|
|
|
#define safe_add5(_ptr, _A, _B, _C, _D, _E) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_E) __sio(var)(e) = (_E); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_add(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_add(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_add(&(__sio(var)(r)), __sio(var)(r), __sio(var)(d)) && \
|
|
safe_add((_ptr), __sio(var)(r), __sio(var)(e))); })
|
|
|
|
#define safe_sub(_ptr, __a, __b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
typeof(__a) __sio(var)(_a) = (__a); \
|
|
typeof(__b) __sio(var)(_b) = (__b); \
|
|
typeof(_ptr) __sio(var)(p) = (_ptr); \
|
|
if (__sio(m)(assert)(__sio(m)(type_enforce)(__sio(var)(_a), \
|
|
__sio(var)(_b)))) { \
|
|
if (__sio(m)(umax)(__sio(var)(_a)) <= ((typeof(__sio(var)(_a)))0)) { \
|
|
__sio(var)(ok) = safe_ssub(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} else { \
|
|
__sio(var)(ok) = safe_usub(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
/* These are sequentially performed */
|
|
#define safe_sub3(_ptr, _A, _B, _C) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_sub(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_sub((_ptr), __sio(var)(r), __sio(var)(c))); })
|
|
|
|
#define safe_sub4(_ptr, _A, _B, _C, _D) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_sub(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_sub(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_sub((_ptr), __sio(var)(r), (__sio(var)(d)))); })
|
|
|
|
#define safe_sub5(_ptr, _A, _B, _C, _D, _E) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_E) __sio(var)(e) = (_E); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_sub(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_sub(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_sub(&(__sio(var)(r)), __sio(var)(r), __sio(var)(d)) && \
|
|
safe_sub((_ptr), __sio(var)(r), __sio(var)(e))); })
|
|
|
|
|
|
|
|
#define safe_mul(_ptr, __a, __b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
typeof(__a) __sio(var)(_a) = (__a); \
|
|
typeof(__b) __sio(var)(_b) = (__b); \
|
|
typeof(_ptr) __sio(var)(p) = (_ptr); \
|
|
if (__sio(m)(assert)(__sio(m)(type_enforce)(__sio(var)(_a), \
|
|
__sio(var)(_b)))) { \
|
|
if (__sio(m)(umax)(__sio(var)(_a)) <= ((typeof(__sio(var)(_a)))0)) { \
|
|
__sio(var)(ok) = safe_smul(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} else { \
|
|
__sio(var)(ok) = safe_umul(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_mul3(_ptr, _A, _B, _C) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_mul(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_mul((_ptr), __sio(var)(r), __sio(var)(c))); })
|
|
|
|
#define safe_mul4(_ptr, _A, _B, _C, _D) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_mul(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_mul(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_mul((_ptr), __sio(var)(r), (__sio(var)(d)))); })
|
|
|
|
#define safe_mul5(_ptr, _A, _B, _C, _D, _E) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_E) __sio(var)(e) = (_E); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_mul(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_mul(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_mul(&(__sio(var)(r)), __sio(var)(r), __sio(var)(d)) && \
|
|
safe_mul((_ptr), __sio(var)(r), __sio(var)(e))); })
|
|
|
|
#define safe_div(_ptr, __a, __b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
typeof(__a) __sio(var)(_a) = (__a); \
|
|
typeof(__b) __sio(var)(_b) = (__b); \
|
|
typeof(_ptr) __sio(var)(p) = (_ptr); \
|
|
if (__sio(m)(assert)(__sio(m)(type_enforce)(__sio(var)(_a), \
|
|
__sio(var)(_b)))) { \
|
|
if (__sio(m)(umax)(__sio(var)(_a)) <= ((typeof(__sio(var)(_a)))0)) { \
|
|
__sio(var)(ok) = safe_sdiv(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} else { \
|
|
__sio(var)(ok) = safe_udiv(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_div3(_ptr, _A, _B, _C) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_div(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_div((_ptr), __sio(var)(r), __sio(var)(c))); })
|
|
|
|
#define safe_div4(_ptr, _A, _B, _C, _D) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_div(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_div(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_div((_ptr), __sio(var)(r), (__sio(var)(d)))); })
|
|
|
|
#define safe_div5(_ptr, _A, _B, _C, _D, _E) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_E) __sio(var)(e) = (_E); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_div(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_div(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_div(&(__sio(var)(r)), __sio(var)(r), __sio(var)(d)) && \
|
|
safe_div((_ptr), __sio(var)(r), __sio(var)(e))); })
|
|
|
|
#define safe_mod(_ptr, __a, __b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
typeof(__a) __sio(var)(_a) = (__a); \
|
|
typeof(__b) __sio(var)(_b) = (__b); \
|
|
typeof(_ptr) __sio(var)(p) = (_ptr); \
|
|
if (__sio(m)(assert)(__sio(m)(type_enforce)(__sio(var)(_a), \
|
|
__sio(var)(_b)))) { \
|
|
if (__sio(m)(umax)(__sio(var)(_a)) <= ((typeof(__sio(var)(_a)))0)) { \
|
|
__sio(var)(ok) = safe_smod(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} else { \
|
|
__sio(var)(ok) = safe_umod(__sio(var)(p), \
|
|
__sio(var)(_a), \
|
|
__sio(var)(_b)); \
|
|
} \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_mod3(_ptr, _A, _B, _C) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_mod(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_mod((_ptr), __sio(var)(r), __sio(var)(c))); })
|
|
|
|
#define safe_mod4(_ptr, _A, _B, _C, _D) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C); \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_mod(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_mod(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_mod((_ptr), __sio(var)(r), (__sio(var)(d)))); })
|
|
|
|
#define safe_mod5(_ptr, _A, _B, _C, _D, _E) \
|
|
({ typeof(_A) __sio(var)(a) = (_A); \
|
|
typeof(_B) __sio(var)(b) = (_B); \
|
|
typeof(_C) __sio(var)(c) = (_C), \
|
|
typeof(_D) __sio(var)(d) = (_D); \
|
|
typeof(_E) __sio(var)(e) = (_E); \
|
|
typeof(_A) __sio(var)(r) = 0; \
|
|
(safe_mod(&(__sio(var)(r)), __sio(var)(a), __sio(var)(b)) && \
|
|
safe_mod(&(__sio(var)(r)), __sio(var)(r), __sio(var)(c)) && \
|
|
safe_mod(&(__sio(var)(r)), __sio(var)(r), __sio(var)(d)) && \
|
|
safe_mod((_ptr), __sio(var)(r), __sio(var)(e))); })
|
|
|
|
/*** Safe integer operation implementation macros ***/
|
|
|
|
#define safe_uadd(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if ((typeof(_a))(_b) <= (typeof(_a))(__sio(m)(umax)(_a) - (_a))) { \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) + (_b); } \
|
|
__sio(var)(ok) = 1; \
|
|
} __sio(var)(ok); })
|
|
|
|
#define safe_sadd(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 1; \
|
|
if (((_b) > (typeof(_a))0) && ((_a) > (typeof(_a))0)) { /*>0*/ \
|
|
if ((_a) > (typeof(_a))(__sio(m)(smax)(_a) - (_b))) __sio(var)(ok) = 0; \
|
|
} else if (!((_b) > (typeof(_a))0) && !((_a) > (typeof(_a))0)) { /*<0*/ \
|
|
if ((_a) < (typeof(_a))(__sio(m)(smin)(_a) - (_b))) __sio(var)(ok) = 0; \
|
|
} \
|
|
if (__sio(var)(ok) && (_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) + (_b); } \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_usub(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if ((_a) >= (_b)) { \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) - (_b); } \
|
|
__sio(var)(ok) = 1; \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_ssub(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if (!((_b) <= 0 && (_a) > (__sio(m)(smax)(_a) + (_b))) && \
|
|
!((_b) > 0 && (_a) < (__sio(m)(smin)(_a) + (_b)))) { \
|
|
__sio(var)(ok) = 1; \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) - (_b); } \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_umul(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if (!(_b) || (_a) <= (__sio(m)(umax)(_a) / (_b))) { \
|
|
__sio(var)(ok) = 1; \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) * (_b); } \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_smul(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 1; \
|
|
if ((_a) > 0) { /* a is positive */ \
|
|
if ((_b) > 0) { /* b and a are positive */ \
|
|
if ((_a) > (__sio(m)(smax)(_a) / (_b))) { \
|
|
__sio(var)(ok) = 0; \
|
|
} \
|
|
} /* end if a and b are positive */ \
|
|
else { /* a positive, b non-positive */ \
|
|
if ((_b) < (__sio(m)(smin)(_a) / (_a))) { \
|
|
__sio(var)(ok) = 0; \
|
|
} \
|
|
} /* a positive, b non-positive */ \
|
|
} /* end if a is positive */ \
|
|
else { /* a is non-positive */ \
|
|
if ((_b) > 0) { /* a is non-positive, b is positive */ \
|
|
if ((_a) < (__sio(m)(smin)(_a) / (_b))) { \
|
|
__sio(var)(ok) = 0; \
|
|
} \
|
|
} /* end if a is non-positive, b is positive */ \
|
|
else { /* a and b are non-positive */ \
|
|
if( ((_a) != 0) && ((_b) < (__sio(m)(smax)(_a) / (_a)))) { \
|
|
__sio(var)(ok) = 0; \
|
|
} \
|
|
} /* end if a and b are non-positive */ \
|
|
} /* end if a is non-positive */ \
|
|
if (__sio(var)(ok) && (_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) * (_b); } \
|
|
__sio(var)(ok); })
|
|
|
|
/* div-by-zero is the only thing addressed */
|
|
#define safe_udiv(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if ((_b) != 0) { \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) / (_b); } \
|
|
__sio(var)(ok) = 1; \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
/* Addreses div by zero and smin -1 */
|
|
#define safe_sdiv(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if ((_b) != 0 && \
|
|
(((_a) != __sio(m)(smin)(_a)) || ((_b) != (typeof(_b))-1))) { \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) / (_b); } \
|
|
__sio(var)(ok) = 1; \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_umod(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if ((_b) != 0) { \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) % (_b); } \
|
|
__sio(var)(ok) = 1; \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#define safe_smod(_ptr, _a, _b) \
|
|
({ int __sio(var)(ok) = 0; \
|
|
if ((_b) != 0 && \
|
|
(((_a) != __sio(m)(smin)(_a)) || ((_b) != (typeof(_b))-1))) { \
|
|
if ((_ptr)) { *((typeof(_a)*)(_ptr)) = (_a) % (_b); } \
|
|
__sio(var)(ok) = 1; \
|
|
} \
|
|
__sio(var)(ok); })
|
|
|
|
#if SAFE_IOP_COMPAT
|
|
/* These are used for testing for easy type enforcement */
|
|
#include <sys/types.h>
|
|
#include <limits.h>
|
|
|
|
#ifndef SAFE_IOP_INLINE
|
|
# if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
|
|
# define SAFE_IOP_INLINE __attribute__((always_inline)) static inline
|
|
# else
|
|
# define SAFE_IOP_INLINE static inline
|
|
# endif
|
|
#endif
|
|
|
|
#define MAKE_UADD(_prefix, _bits, _type, _max) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_add##_prefix##_bits (_type *result, _type value, _type a) { \
|
|
return safe_uadd(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_SADD(_prefix, _bits, _type, _max) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_add##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_sadd(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_USUB(_prefix, _bits, _type) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_sub##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_usub(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_SSUB(_prefix, _bits, _type, _min, _max) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_sub##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_ssub(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_UMUL(_prefix, _bits, _type, _max) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_mul##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_umul(result, value, a); \
|
|
}
|
|
|
|
|
|
#define MAKE_SMUL(_prefix, _bits, _type, _max, _min) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_mul##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_smul(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_UDIV(_prefix, _bits, _type) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_div##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_udiv(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_SDIV(_prefix, _bits, _type, _min) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_div##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_sdiv(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_UMOD(_prefix, _bits, _type) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_mod##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_umod(result, value, a); \
|
|
}
|
|
|
|
#define MAKE_SMOD(_prefix, _bits, _type, _min) \
|
|
SAFE_IOP_INLINE \
|
|
int safe_mod##_prefix##_bits(_type *result, _type value, _type a) { \
|
|
return safe_smod(result, value, a); \
|
|
}
|
|
|
|
/* __LP64__ is given by GCC. Without more work, this is bound to GCC. */
|
|
#if __LP64__ == 1 || __SIZEOF_LONG__ > __SIZEOF_INT__
|
|
# define SAFE_INT64_MAX 0x7fffffffffffffffL
|
|
# define SAFE_UINT64_MAX 0xffffffffffffffffUL
|
|
# define SAFE_INT64_MIN (-SAFE_INT64_MAX - 1L)
|
|
#elif __SIZEOF_LONG__ == __SIZEOF_INT__
|
|
# define SAFE_INT64_MAX 0x7fffffffffffffffLL
|
|
# define SAFE_UINT64_MAX 0xffffffffffffffffULL
|
|
# define SAFE_INT64_MIN (-SAFE_INT64_MAX - 1LL)
|
|
#else
|
|
# warning "64-bit support disabled"
|
|
# define SAFE_IOP_NO_64 1
|
|
#endif
|
|
|
|
/* Assumes SSIZE_MAX */
|
|
#ifndef SSIZE_MIN
|
|
# if SSIZE_MAX == LONG_MAX
|
|
# define SSIZE_MIN LONG_MIN
|
|
# elif SSIZE_MAX == LONG_LONG_MAX
|
|
# define SSIZE_MIN LONG_LONG_MIN
|
|
# else
|
|
# error "SSIZE_MIN is not defined and could not be guessed"
|
|
# endif
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_UADD(u, 64, u_int64_t, SAFE_UINT64_MAX)
|
|
#endif
|
|
MAKE_UADD(,szt, size_t, SIZE_MAX)
|
|
MAKE_UADD(u, 32, u_int32_t, UINT_MAX)
|
|
MAKE_UADD(u, 16, u_int16_t, USHRT_MAX)
|
|
MAKE_UADD(u, 8, u_int8_t, UCHAR_MAX)
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_SADD(s, 64, int64_t, SAFE_INT64_MAX)
|
|
#endif
|
|
MAKE_SADD(s, szt, ssize_t, SSIZE_MAX)
|
|
MAKE_SADD(s, 32, int32_t, INT_MAX)
|
|
MAKE_SADD(s, 16, int16_t, SHRT_MAX)
|
|
MAKE_SADD(s, 8, int8_t, SCHAR_MAX)
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_USUB(u, 64, u_int64_t)
|
|
#endif
|
|
MAKE_USUB(, szt, size_t)
|
|
MAKE_USUB(u, 32, u_int32_t)
|
|
MAKE_USUB(u, 16, u_int16_t)
|
|
MAKE_USUB(u, 8, u_int8_t)
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_SSUB(s, 64, int64_t, SAFE_INT64_MIN, SAFE_INT64_MAX)
|
|
#endif
|
|
MAKE_SSUB(s, szt, ssize_t, SSIZE_MIN, SSIZE_MAX)
|
|
MAKE_SSUB(s, 32, int32_t, INT_MIN, INT_MAX)
|
|
MAKE_SSUB(s, 16, int16_t, SHRT_MIN, SHRT_MAX)
|
|
MAKE_SSUB(s, 8, int8_t, SCHAR_MIN, SCHAR_MAX)
|
|
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_UMUL(u, 64, u_int64_t, SAFE_UINT64_MAX)
|
|
#endif
|
|
MAKE_UMUL(, szt, size_t, SIZE_MAX)
|
|
MAKE_UMUL(u, 32, u_int32_t, UINT_MAX)
|
|
MAKE_UMUL(u, 16, u_int16_t, USHRT_MAX)
|
|
MAKE_UMUL(u, 8, u_int8_t, UCHAR_MAX)
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_SMUL(s, 64, int64_t, SAFE_INT64_MAX, SAFE_INT64_MIN)
|
|
#endif
|
|
MAKE_SMUL(s, szt, ssize_t, SSIZE_MAX, SSIZE_MIN)
|
|
MAKE_SMUL(s, 32, int32_t, INT_MAX, INT_MIN)
|
|
MAKE_SMUL(s, 16, int16_t, SHRT_MAX, SHRT_MIN)
|
|
MAKE_SMUL(s, 8, int8_t, SCHAR_MAX, SCHAR_MIN)
|
|
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_UDIV(u, 64, u_int64_t)
|
|
#endif
|
|
MAKE_UDIV(, szt, size_t)
|
|
MAKE_UDIV(u, 32, u_int32_t)
|
|
MAKE_UDIV(u, 16, u_int16_t)
|
|
MAKE_UDIV(u, 8, u_int8_t)
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_SDIV(s, 64, int64_t, SAFE_INT64_MIN)
|
|
#endif
|
|
MAKE_SDIV(s, szt, ssize_t, SSIZE_MIN)
|
|
MAKE_SDIV(s, 32, int32_t, INT_MIN)
|
|
MAKE_SDIV(s, 16, int16_t, SHRT_MIN)
|
|
MAKE_SDIV(s, 8, int8_t, SCHAR_MIN)
|
|
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_UMOD(u, 64, u_int64_t)
|
|
#endif
|
|
MAKE_UMOD(, szt, size_t)
|
|
MAKE_UMOD(u, 32, u_int32_t)
|
|
MAKE_UMOD(u, 16, u_int16_t)
|
|
MAKE_UMOD(u, 8, u_int8_t)
|
|
|
|
#ifndef SAFE_IOP_NO_64
|
|
MAKE_SMOD(s, 64, int64_t, SAFE_INT64_MIN)
|
|
#endif
|
|
MAKE_SMOD(s, szt, ssize_t, SSIZE_MIN)
|
|
MAKE_SMOD(s, 32, int32_t, INT_MIN)
|
|
MAKE_SMOD(s, 16, int16_t, SHRT_MIN)
|
|
MAKE_SMOD(s, 8, int8_t, SCHAR_MIN)
|
|
|
|
/* Cleanup the macro spam */
|
|
#undef MAKE_SMUL
|
|
#undef MAKE_UMUL
|
|
#undef MAKE_SSUB
|
|
#undef MAKE_USUB
|
|
#undef MAKE_SADD
|
|
#undef MAKE_UADD
|
|
#undef MAKE_UDIV
|
|
#undef MAKE_SDIV
|
|
#undef MAKE_UMOD
|
|
#undef MAKE_SMOD
|
|
|
|
#endif /* SAFE_IOP_COMPAT */
|
|
|
|
|
|
|
|
/* safe_iopf
|
|
*
|
|
* Takes in a character array which specifies the operations
|
|
* to perform on a given value. The value will be assumed to be
|
|
* of the type specified for each operation.
|
|
*
|
|
* Currently accepted format syntax is:
|
|
* [type_marker]operation...
|
|
* The type marker may be any of the following:
|
|
* - s32 for signed int32
|
|
* - u32 for unsigned int32
|
|
* If no type_marker is specified, it is assumed to be s32.
|
|
*
|
|
* Currently, this only performs correctly with 32-bit integers.
|
|
*
|
|
* The operation must be one of the following:
|
|
* - * -- multiplication
|
|
* - / -- division
|
|
* - - -- subtraction
|
|
* - + -- addition
|
|
* - % -- modulo (remainder)
|
|
*
|
|
* Whitespace will be ignored.
|
|
*
|
|
* Args:
|
|
* - pointer to the final result (this must be at least the size of int32)
|
|
* - array of format characters
|
|
* - all remaining arguments are derived from the format
|
|
* Output:
|
|
* - Returns 1 on success leaving the result in value
|
|
* - Returns 0 on failure leaving the contents of value *unknown*
|
|
*/
|
|
|
|
int safe_iopf(void *result, const char *const fmt, ...);
|
|
|
|
|
|
#endif /* _SAFE_IOP_H */
|