external/safe-iop 0.3.1
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..499c813
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,44 @@
+#
+# safe_iop - Makefile
+#
+# Author:: Will Drewry <redpig@dataspill.org>
+# Copyright 2007,2008 redpig@dataspill.org
+# Some portions copyright 2008 Google Inc.
+#
+# 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.
+#
+
+CC = gcc
+VERSION = 0.3
+TESTNAME = safe_iop_test
+# For sparc64, _only_ use -O1 or -O0
+CFLAGS   = -Wall -O2 -Iinclude
+SOURCES = src/safe_iop.c
+
+all: $(TESTNAME)
+
+# This may be built as a library or directly included in source.
+# Unless support for safe_iopf is needed, header inclusion is enough.
+
+$(TESTNAME): src/safe_iop.c include/safe_iop.h
+	$(CC) $(CFLAGS) -DNDEBUG=1 -DSAFE_IOP_TEST=1 $(SOURCES) -o $@
+
+askme: examples/askme.c include/safe_iop.h
+	$(CC) $(CFLAGS) examples/askme.c -o $@
+
+so: src/safe_iop.c include/safe_iop.h
+	$(CC) -shared -Wl,-soname,libsafe_iop.so.$(VERSION) $(CFLAGS) $(SOURCES) -o libsafe_iop.so.$(VERSION) 
+
+dylib: src/safe_iop.c include/safe_iop.h
+	$(CC) -dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,$(VERSION),-current_version,$(VERSION),-install_name,/usr/local/lib/libsafe_iop.$(VERSION).dylib $(CFLAGS) $(SOURCES) -o libsafe_iop.$(VERSION).dylib
+
+
+test: $(TESTNAME)
+	@./$(TESTNAME)
+	@rm $(TESTNAME)
+
+clean:  
+	rm $(TESTNAME)
+
diff --git a/README b/README
new file mode 100644
index 0000000..daf5c2d
--- /dev/null
+++ b/README
@@ -0,0 +1,136 @@
+safe_iop - a safe integer operation library for C
+Will Drewry <redpig@dataspill.org>
+
+= Copyright and Licensing
+Copyright 2007-2008, Will Drewry <redpig@dataspill.org>
+Some portions copyright 2008 Google Inc
+Released into the public domain with no warranty and no guarantees
+
+= Introduction
+
+Unsafe integer operations are a major cause of software defects even in modern
+day software.  C is the underlying language for most high level languages
+(Ruby, Python, Java, etc) in addition to being in widespread general use.
+C is a preferred language for high performance programming and is
+often used for media file parsing and manipulation. 
+
+Integer overflows occur when the calculated integer requires more storage from
+the computing platform than is available.  If a number is too large, not all of
+its information can be stored.  This has dangerous side effects. For a detailed
+and thorough discussion on integer overflows, please check out CERT's website
+on Secure Coding[1] and even Wikipedia[2].
+
+[1] https://www.securecoding.cert.org/confluence/display/seccode/CERT+C+Secure+Coding+Standard
+[2] http://en.wikipedia.org/wiki/Integer_overflow
+
+
+= Requirements
+
+safe_iop was designed explicitly with GNU GCC in mind and has only been tested
+with it.  Your mileage may vary.  Please let me know if it works for you with
+different compilers or on different platforms, and I'll update the Compatibility
+section below!
+
+In addition, your system must supply limits.h and assert.h for safe_iop to
+function as expected.  It is possible to remove the dependence on both, but it
+breaks general portability.
+
+= Usage
+
+safe_iop comes in two pieces, safe_iop.h and safe_iop.c.  safe_iop.h provides
+extensive macros for performing safe integer operations quickly and easily.
+safe_iop.c contains some testing code to make sure the package works on your
+system and a preliminary format string interface, safe_iopf.  safe_iopf is not
+for the faint of heart as it is currently under development.  The remainder of
+this document will focus on safe_iop.h.
+
+In order to use safe_iop, you will need to place safe_iop.h in your compiler's
+include path either by copying it somewhere like /usr/include, using an include
+flag -I/opt/safe_iop/include, or whatever other way you prefer. You will then
+need to include the header in the source file you will use the functions from.
+E.g., #include <safe_iop.h>
+
+safe_iop provides macros which check the validity of a given integer operation.
+It supports the following operations:
+- multiplication: safe_mul()
+- division:       safe_div()
+- addition:       safe_add()
+- subtraction:    safe_sub()
+
+All of these macros take a result pointer, or NULL, as the first argument.  The
+subsequent argument should be the two values to operate on.  They then return
+true or false depending on if the operation is safe or not. (If NULL is given,
+a true or false value will be returned.) 
+
+  uint32_t a = 100, b = 200, c = 0;
+  if (safe_mul(&c, a, b)) printf("c is %u\n", c);
+
+In addition, there are versions of these functions for multiple sequential operations:
+
+  uint32_t a = 100, b = 200, c = 300, d = 0;
+  if (safe_mul3(&d, a, b, c)) printf("d is %u\n", d);
+
+safe_<op>3-5() are all available.
+
+It is important to note that if the types of integers passed to safe_iop do not
+match, the operation will return false (0) with -DNDEBUG defined.  If it is not
+defined, assert() is called and the program will abort if these mismatch is
+seen!
+
+For example,
+  uint32_t a = 100, c = 0;
+  uint8_t b = 20;
+  if (safe_add(&c, a, b)) /* I will return false! */
+
+
+Examples can be found in the examples/ directory.
+
+== safe_iopf
+
+If you'd like to use the format string function, do so at your own peril :-)
+If you like it and would like to send me a patch to make it awesome, I'd
+appreciate it!  To use, just include the c file in your build, or build the
+shared library and link it to your app:
+  make so # or make dylib for OS X 
+  ...
+  gcc yourapp.c ... -lsafe_iop
+
+More to come!
+
+= Compatibility
+
+Tests pass on the following platforms:
+
+- OS X Tiger, x86, GNU GCC 4.0.1
+- OS X Leopard, x86, GNU GCC 4.0.1
+- GNU/Linux, x86, GNU GCC 4.0.3
+- GNU/Linux, x86_64, GNU GCC 4.0.3
+- OpenBSD, VAX, GNU GCC 2.95.3
+- OpenBSD, sparc, GNU GCC 2.95.3
+- OpenBSD, alpha, GNU GCC 3.3.5
+- OpenBSD, sparc, GNU GCC 2.95.3
+- OpenBSD, macppc, GNU GCC 3.3.5
+- OpenBSD, arm, GNU GCC 3.3.5 
+~ OpenBSD, sparc64, GNU GCC 3.3.5 [1]
+
+[1] For sparc64, there is an optimization bug which causes tests to fail if
+    -O<level> exceeds 1.
+
+= Credit where credit is do
+
+- The functions used in this library were largely drawn from the examples
+  provided in CERT's secure coding standard.
+- Thanks to peter@valchev.net for reviews, comments, enthusiasm, and multiple
+  platform tests!
+- Thanks to taviso@sdf.lonestar.org for the pointing out stupid API decisions
+  and cross-checking my logic.
+
+= Changes
+
+The changes and todo list can be found in include/safe_iop.h
+
+= Contributions, corrections, suggestions, flames . . .
+
+Please drop me an email if I'm doing something completely stupid, you love
+using the library, you have a patch or recommendation, or for whatever other
+reason.  I hope this software helps out a bit!
diff --git a/examples/askme.c b/examples/askme.c
new file mode 100644
index 0000000..dcb4267
--- /dev/null
+++ b/examples/askme.c
@@ -0,0 +1,20 @@
+#include <stdio.h>  /* for printf, fgets */
+#include <stdlib.h>  /* for atoi */
+#include <stdint.h> /* for uint32_t */
+#include <safe_iop.h> /* for awesomeness */
+
+int main(int argc, char **argv) {
+  char buf[1024];
+  uint32_t width = 0, height = 0, pixels = 0;
+  printf("Please specify the width of the new image: ");
+  width = strtoul(fgets(buf, 1023, stdin), NULL, 10);
+  printf("Please specify the height of the new image: ");
+  height = strtoul(fgets(buf, 1023, stdin), NULL, 10);
+  if (safe_mul(&pixels, width, height)) {
+    printf("The resulting image will have %u pixels.\n", pixels);
+    return 0;
+  } else {
+    printf("Image size specified exceeds maximum size!\n");
+    return 1;
+  }
+}
diff --git a/include/safe_iop.h b/include/safe_iop.h
new file mode 100644
index 0000000..bb3b8c4
--- /dev/null
+++ b/include/safe_iop.h
@@ -0,0 +1,699 @@
+/* safe_iop
+ * License:: released in to the public domain
+ * Author:: Will Drewry <redpig@dataspill.org>
+ * Copyright 2007,2008 redpig@dataspill.org
+ * Some portions copyright Google Inc, 2008.
+ *
+ * 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 */
diff --git a/src/safe_iop.c b/src/safe_iop.c
new file mode 100644
index 0000000..adbe37c
--- /dev/null
+++ b/src/safe_iop.c
@@ -0,0 +1,1177 @@
+/* safe_iop
+ * License:: released in to the public domain
+ * Author:: Will Drewry <redpig@dataspill.org>
+ * Copyright 2007,2008 redpig@dataspill.org
+ * Some portions copyright Google Inc, 2008.
+ *
+ * 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.
+ *
+ * See safe_iop.h for more info.
+ */
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <safe_iop.h>
+
+/* Read off the type if the first value matches a type prefix
+ * and consume characters if successful.
+ */
+static int _safe_op_read_type(safe_type_t *type, const char **c) {
+  if (type == NULL) {
+    return 0;
+  }
+  if (c == NULL || *c == NULL || **c == '\0') {
+    return 0;
+  }
+  /* Extract a type for the operation if there is one */
+  if (strchr(SAFE_IOP_TYPE_PREFIXES, **c) != NULL) {
+    switch(**c) {
+      case 'u':
+        if ((*(*c+1) && *(*c+1) == '3') &&
+            (*(*c+2) && *(*c+2) == '2')) {
+          *type = SAFE_IOP_TYPE_U32;
+          *c += 3; /* Advance past type */
+        }
+        break;
+      case 's':
+        if ((*(*c+1) && *(*c+1) == '3') &&
+            (*(*c+2) && *(*c+2) == '2')) {
+          *type = SAFE_IOP_TYPE_S32;
+          *c += 3; /* Advance past type */
+        }
+        break;
+      default:
+        /* Unknown type */
+        return 0;
+    }
+  }
+  return 1;
+}
+
+#define _SAFE_IOP_TYPE_CASE(_type, _func) { \
+  _type a = va_arg(ap, _type), value = *((_type *) result); \
+  if (!baseline) { \
+    value = a; \
+    a = va_arg(ap, _type); \
+    baseline = 1; \
+  } \
+  if (! _func( (_type *) result, value, a)) \
+    return 0; \
+}
+#define _SAFE_IOP_OP_CASE(u32func, s32func) \
+  switch (type) { \
+    case SAFE_IOP_TYPE_U32: \
+      _SAFE_IOP_TYPE_CASE(u_int32_t, u32func); \
+      break; \
+    case SAFE_IOP_TYPE_S32: \
+      _SAFE_IOP_TYPE_CASE(int32_t, s32func); \
+      break; \
+    default: \
+      return 0; \
+  }
+
+int safe_iopf(void *result, const char *const fmt, ...) {
+  va_list ap;
+  int baseline = 0; /* indicates if the base value is present */
+
+  const char *c = NULL;
+  safe_type_t type = SAFE_IOP_TYPE_DEFAULT;
+  /* Result should not be NULL */
+  if (!result)
+    return 0;
+
+  va_start(ap, fmt);
+  if (fmt == NULL || fmt[0] == '\0')
+    return 0;
+  for(c=fmt;(*c);c++) {
+    /* Read the type if specified */
+    if (!_safe_op_read_type(&type, &c)) {
+      return 0;
+    }
+
+    /* Process the the operations */
+    switch(*c) { /* operation */
+      case '+': /* add */
+        _SAFE_IOP_OP_CASE(safe_uadd, safe_sadd);
+        break;
+      case '-': /* sub */
+        _SAFE_IOP_OP_CASE(safe_usub, safe_ssub);
+        break;
+      case '*': /* mul */
+        _SAFE_IOP_OP_CASE(safe_umul, safe_smul);
+        break;
+      case '/': /* div */
+        _SAFE_IOP_OP_CASE(safe_udiv, safe_sdiv);
+        break;
+      case '%': /* mod */
+        _SAFE_IOP_OP_CASE(safe_umod, safe_smod);
+        break;
+      default:
+       /* unknown op */
+       return 0;
+    }
+    /* Reset the type */
+   type = SAFE_IOP_TYPE_DEFAULT;
+  }
+  /* Success! */
+  return 1;
+}
+
+#ifdef SAFE_IOP_TEST
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+
+/* __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
+
+/* Pull these from GNU's limit.h */
+#ifndef LLONG_MAX
+#  define LLONG_MAX 9223372036854775807LL
+#endif
+#ifndef LLONG_MIN
+#  define LLONG_MIN (-LLONG_MAX - 1LL)
+#endif
+#ifndef ULLONG_MAX
+#  define ULLONG_MAX 18446744073709551615ULL
+#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
+
+#define EXPECT_FALSE(cmd) ({ \
+  printf("%s: EXPECT_FALSE(" #cmd ") => ", __func__); \
+  if ((cmd) != 0) { printf(" FAILED\n"); expect_fail++; r = 0; } \
+  else { printf(" PASSED\n"); expect_succ++; } \
+  expect++; \
+  })
+#define EXPECT_TRUE(cmd) ({ \
+  printf("%s: EXPECT_TRUE(" #cmd ") => ", __func__); \
+  if ((cmd) != 1) { printf(" FAILED\n"); expect_fail++; r = 0; } \
+  else { printf(" PASSED\n"); expect_succ++; } \
+  expect++;  \
+  })
+
+static int expect = 0, expect_succ = 0, expect_fail = 0;
+
+/***** ADD *****/
+int T_add_s8() {
+  int r=1;
+  int8_t a, b;
+  a=SCHAR_MIN; b=-1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SCHAR_MAX; b=1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=-10; b=-11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SCHAR_MIN; b=SCHAR_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SCHAR_MIN+1; b=-1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SCHAR_MAX/2; b=SCHAR_MAX/2; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_s16() {
+  int r=1;
+  int16_t a, b;
+  a=SHRT_MIN; b=-1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SHRT_MAX; b=1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SHRT_MIN; b=SHRT_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SHRT_MAX/2; b=SHRT_MAX/2; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_s32() {
+  int r=1;
+  int32_t a, b;
+  a=INT_MIN; b=-1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=INT_MAX; b=1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=INT_MIN; b=INT_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=INT_MAX/2; b=INT_MAX/2; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_s64() {
+  int r=1;
+  int64_t a, b;
+  a=SAFE_INT64_MIN; b=-1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SAFE_INT64_MAX; b=1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SAFE_INT64_MIN; b=SAFE_INT64_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SAFE_INT64_MAX/2; b=SAFE_INT64_MAX/2; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_long() {
+  int r=1;
+  long a, b;
+  a=LONG_MIN; b=-1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=LONG_MAX; b=1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=LONG_MIN; b=LONG_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=LONG_MAX/2; b=LONG_MAX/2; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+int T_add_longlong() {
+  int r=1;
+  long long a, b;
+  a=LLONG_MIN; b=-1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=LLONG_MAX; b=1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=LLONG_MIN; b=LLONG_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=LLONG_MAX/2; b=LLONG_MAX/2; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+int T_add_ssizet() {
+  int r=1;
+  ssize_t a, b;
+  a=SSIZE_MIN; b=-1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SSIZE_MAX; b=1; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SSIZE_MIN; b=SSIZE_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SSIZE_MAX/2; b=SSIZE_MAX/2; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_u8() {
+  int r=1;
+  uint8_t a, b;
+  a=1; b=UCHAR_MAX; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=UCHAR_MAX/2; b=a+2; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=UCHAR_MAX/2; b=a; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=UCHAR_MAX/2; b=a+1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=0; b=UCHAR_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_u16() {
+  int r=1;
+  uint16_t a, b;
+  a=1; b=USHRT_MAX; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=USHRT_MAX/2; b=a+2; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=USHRT_MAX/2; b=a; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=USHRT_MAX/2; b=a+1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=0; b=USHRT_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_u32() {
+  int r=1;
+  uint32_t a, b;
+  a=1; b=UINT_MAX; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=UINT_MAX/2; b=a+2; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=UINT_MAX/2; b=a; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=UINT_MAX/2; b=a+1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=0; b=UINT_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_u64() {
+  int r=1;
+  uint64_t a, b;
+  a=1; b=SAFE_UINT64_MAX; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SAFE_UINT64_MAX/2; b=a+2; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SAFE_UINT64_MAX/2; b=a; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SAFE_UINT64_MAX/2; b=a+1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=0; b=SAFE_UINT64_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_ulong() {
+  int r=1;
+  unsigned long a, b;
+  a=1; b=ULONG_MAX; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=ULONG_MAX/2; b=a+2; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=ULONG_MAX/2; b=a; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=ULONG_MAX/2; b=a+1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=0; b=ULONG_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_ulonglong() {
+  int r=1;
+  unsigned long long a, b;
+  a=1; b=ULLONG_MAX; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=ULLONG_MAX/2; b=a+2; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=ULLONG_MAX/2; b=a; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=ULLONG_MAX/2; b=a+1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=0; b=ULLONG_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_sizet() {
+  int r=1;
+  size_t a, b;
+  a=1; b=SIZE_MAX; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SIZE_MAX/2; b=a+2; EXPECT_FALSE(safe_add(NULL, a, b));
+  a=SIZE_MAX/2; b=a; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=SIZE_MAX/2; b=a+1; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=10; b=11; EXPECT_TRUE(safe_add(NULL, a, b));
+  a=0; b=SIZE_MAX; EXPECT_TRUE(safe_add(NULL, a, b));
+  return r;
+}
+
+int T_add_mixed() {
+  int r=1;
+  int8_t a = 1;
+  uint8_t b = 2;
+  uint16_t c = 3;
+  EXPECT_FALSE(safe_add(NULL, a, b));
+  EXPECT_FALSE(safe_add(NULL, b, c));
+  EXPECT_FALSE(safe_add(NULL, a, c));
+  EXPECT_FALSE(safe_add3(NULL, a, b, c));
+  return r;
+}
+
+int T_add_increment() {
+  int r=1;
+  uint16_t a = 1, b = 2, c = 0, d[2]= {0};
+  uint16_t *cur = d;
+  EXPECT_TRUE(safe_add(cur++, a++, b));
+  EXPECT_TRUE(cur == &d[1]);
+  EXPECT_TRUE(d[0] == 3);
+  EXPECT_TRUE(a == 2);
+  a = 1; b = 2; c = 1; cur=d;d[0] = 0;
+  EXPECT_TRUE(safe_add3(cur++, a++, b++, c));
+  EXPECT_TRUE(d[0] == 4);
+  EXPECT_TRUE(cur == &d[1]);
+  EXPECT_TRUE(a == 2);
+  EXPECT_TRUE(b == 3);
+  EXPECT_TRUE(c == 1);
+  return r;
+}
+
+
+
+/***** SUB *****/
+int T_sub_s8() {
+  int r=1;
+  int8_t a, b;
+  a=SCHAR_MIN; b=1; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SCHAR_MIN; b=SCHAR_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SCHAR_MIN/2; b=SCHAR_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=-2; b=SCHAR_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SCHAR_MAX; b=SCHAR_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=2; b=10; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_s16() {
+  int r=1;
+  int16_t a, b;
+  a=SHRT_MIN; b=1; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SHRT_MIN; b=SHRT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SHRT_MIN/2; b=SHRT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=-2; b=SHRT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SHRT_MAX; b=SHRT_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=2; b=10; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_s32() {
+  int r=1;
+  int32_t a, b;
+  a=INT_MIN; b=1; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=INT_MIN; b=INT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=INT_MIN/2; b=INT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=-2; b=INT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=INT_MAX; b=INT_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=2; b=10; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_s64() {
+  int r=1;
+  int64_t a, b;
+  a=SAFE_INT64_MIN; b=1; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SAFE_INT64_MIN; b=SAFE_INT64_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SAFE_INT64_MIN/2; b=SAFE_INT64_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=-2; b=SAFE_INT64_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SAFE_INT64_MAX; b=SAFE_INT64_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=2; b=10; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_long() {
+  int r=1;
+  long a, b;
+  a=LONG_MIN; b=1; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=LONG_MIN; b=LONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=LONG_MIN/2; b=LONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=-2; b=LONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=LONG_MAX; b=LONG_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=2; b=10; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_longlong() {
+  int r=1;
+  long long a, b;
+  a=LLONG_MIN; b=1; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=LLONG_MIN; b=LLONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=LLONG_MIN/2; b=LLONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=-2; b=LLONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=LLONG_MAX; b=LLONG_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=2; b=10; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_ssizet() {
+  int r=1;
+  ssize_t a, b;
+  a=SSIZE_MIN; b=1; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SSIZE_MIN; b=SSIZE_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SSIZE_MIN/2; b=SSIZE_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=-2; b=SSIZE_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SSIZE_MAX; b=SSIZE_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=2; b=10; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_u8() {
+  int r=1;
+  uint8_t a, b;
+  a=0; b=UCHAR_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=UCHAR_MAX-1; b=UCHAR_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=UCHAR_MAX; b=UCHAR_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=1; b=100; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_u16() {
+  int r=1;
+  uint16_t a, b;
+  a=0; b=USHRT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=USHRT_MAX-1; b=USHRT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=USHRT_MAX; b=USHRT_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=1; b=100; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_u32() {
+  int r=1;
+  uint32_t a, b;
+  a=UINT_MAX-1; b=UINT_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=UINT_MAX; b=UINT_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=1; b=100; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_u64() {
+  int r=1;
+  uint64_t a, b;
+  a=SAFE_UINT64_MAX-1; b=SAFE_UINT64_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SAFE_UINT64_MAX; b=SAFE_UINT64_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=1; b=100; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_ulong() {
+  int r=1;
+  unsigned long a, b;
+  a=ULONG_MAX-1; b=ULONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=ULONG_MAX; b=ULONG_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=1; b=100; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_ulonglong() {
+  int r=1;
+  unsigned long long a, b;
+  a=ULLONG_MAX-1; b=ULLONG_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=ULLONG_MAX; b=ULLONG_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=1; b=100; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+int T_sub_sizet() {
+  int r=1;
+  size_t a, b;
+  a=SIZE_MAX-1; b=SIZE_MAX; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=SIZE_MAX; b=SIZE_MAX; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=1; b=100; EXPECT_FALSE(safe_sub(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_sub(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_sub(NULL, a, b));
+  return r;
+}
+
+/***** MUL *****/
+int T_mul_s8() {
+  int r=1;
+  int8_t a, b;
+  a=SCHAR_MIN; b=-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SCHAR_MIN; b=-2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SCHAR_MAX; b=SCHAR_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SCHAR_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SCHAR_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SCHAR_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SCHAR_MIN; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SCHAR_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SCHAR_MIN; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_s16() {
+  int r=1;
+  int16_t a, b;
+  a=SHRT_MIN; b=-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SHRT_MIN; b=-2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SHRT_MAX; b=SHRT_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SHRT_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SHRT_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SHRT_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SHRT_MIN; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SHRT_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SHRT_MIN; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_s32() {
+  int r=1;
+  int32_t a, b;
+  a=INT_MIN; b=-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=INT_MIN; b=-2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=INT_MAX; b=INT_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=INT_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=INT_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=INT_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=INT_MIN; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=INT_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=INT_MIN; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_s64() {
+  int r=1;
+  int64_t a, b;
+  a=SAFE_INT64_MIN; b=-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SAFE_INT64_MIN; b=-2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SAFE_INT64_MAX; b=SAFE_INT64_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SAFE_INT64_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SAFE_INT64_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SAFE_INT64_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SAFE_INT64_MIN; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SAFE_INT64_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SAFE_INT64_MIN; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_long() {
+  int r=1;
+  long a, b;
+  a=LONG_MIN; b=-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LONG_MIN; b=-2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LONG_MAX; b=LONG_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LONG_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LONG_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=LONG_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=LONG_MIN; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=LONG_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=LONG_MIN; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+int T_mul_longlong() {
+  int r=1;
+  long long a, b;
+  a=LLONG_MIN; b=-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LLONG_MIN; b=-2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LLONG_MAX; b=LLONG_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LLONG_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=LLONG_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=LLONG_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=LLONG_MIN; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=LLONG_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=LLONG_MIN; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+int T_mul_ssizet() {
+  int r=1;
+  ssize_t a, b;
+  a=SSIZE_MIN; b=-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SSIZE_MIN; b=-2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SSIZE_MAX; b=SSIZE_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SSIZE_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SSIZE_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=100; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SSIZE_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SSIZE_MIN; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SSIZE_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SSIZE_MIN; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_u8() {
+  int r=1;
+  uint8_t a, b;
+  a=UCHAR_MAX-1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=UCHAR_MAX-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=UCHAR_MAX; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=UCHAR_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=UCHAR_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=UCHAR_MAX/2+1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=UCHAR_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=UCHAR_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=1; b=UCHAR_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=UCHAR_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=UCHAR_MAX; b=1; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_u16() {
+  int r=1;
+  uint16_t a, b;
+  a=USHRT_MAX-1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=USHRT_MAX-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=USHRT_MAX; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=USHRT_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=USHRT_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=USHRT_MAX/2+1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=USHRT_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=USHRT_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=1; b=USHRT_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=USHRT_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=USHRT_MAX; b=1; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_u32() {
+  int r=1;
+  uint32_t a, b;
+  a=UINT_MAX-1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=UINT_MAX-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=UINT_MAX; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=UINT_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=UINT_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=UINT_MAX/2+1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=UINT_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=UINT_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=1; b=UINT_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=UINT_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=UINT_MAX; b=1; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_u64() {
+  int r=1;
+  uint64_t a, b;
+  a=SAFE_UINT64_MAX-1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=SAFE_UINT64_MAX-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SAFE_UINT64_MAX; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=SAFE_UINT64_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SAFE_UINT64_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=SAFE_UINT64_MAX/2+1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SAFE_UINT64_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SAFE_UINT64_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=1; b=SAFE_UINT64_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SAFE_UINT64_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SAFE_UINT64_MAX; b=1; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_ulong() {
+  int r=1;
+  unsigned long a, b;
+  a=ULONG_MAX-1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=ULONG_MAX-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=ULONG_MAX; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=ULONG_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=ULONG_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=ULONG_MAX/2+1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=ULONG_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=ULONG_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=1; b=ULONG_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=ULONG_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=ULONG_MAX; b=1; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_ulonglong() {
+  int r=1;
+  unsigned long long a, b;
+  a=ULLONG_MAX-1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=ULLONG_MAX-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=ULLONG_MAX; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=ULLONG_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=ULLONG_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=ULLONG_MAX/2+1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=ULLONG_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=ULLONG_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=1; b=ULLONG_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=ULLONG_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=ULLONG_MAX; b=1; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+int T_mul_sizet() {
+  int r=1;
+  size_t a, b;
+  a=SIZE_MAX-1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=SIZE_MAX-1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SIZE_MAX; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=SIZE_MAX; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SIZE_MAX/2+1; b=2; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=2; b=SIZE_MAX/2+1; EXPECT_FALSE(safe_mul(NULL, a, b));
+  a=SIZE_MAX/2; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=0; b=SIZE_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=1; b=SIZE_MAX; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SIZE_MAX; b=0; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=SIZE_MAX; b=1; EXPECT_TRUE(safe_mul(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mul(NULL, a, b));
+  return r;
+}
+
+/***** MOD *****/
+int T_mod_s8() {
+  int r=1;
+  int8_t a, b;
+  a=SCHAR_MIN; b=-1; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_s16() {
+  int r=1;
+  int16_t a, b;
+  a=SHRT_MIN; b=-1; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_s32() {
+  int r=1;
+  int32_t a, b;
+  a=INT_MIN; b=-1; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_s64() {
+  int r=1;
+  int64_t a, b;
+  a=SAFE_INT64_MIN; b=-1; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_long() {
+  int r=1;
+  long a, b;
+  a=LONG_MIN; b=-1; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+int T_mod_longlong() {
+  int r=1;
+  long long a, b;
+  a=LLONG_MIN; b=-1LL; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=100LL; b=0LL; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10LL; b=2LL; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+int T_mod_ssizet() {
+  int r=1;
+  ssize_t a, b;
+  a=SSIZE_MIN; b=-1; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_u8() {
+  int r=1;
+  uint8_t a, b;
+  a=0; b=UCHAR_MAX; EXPECT_TRUE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_u16() {
+  int r=1;
+  uint16_t a, b;
+  a=0; b=USHRT_MAX; EXPECT_TRUE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_u32() {
+  int r=1;
+  uint32_t a, b;
+  a=0; b=UINT_MAX; EXPECT_TRUE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_u64() {
+  int r=1;
+  uint64_t a, b;
+  a=0; b=SAFE_INT64_MAX; EXPECT_TRUE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_ulong() {
+  int r=1;
+  unsigned long a, b;
+  a=0; b=LONG_MAX; EXPECT_TRUE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_ulonglong() {
+  int r=1;
+  unsigned long long a, b;
+  a=0ULL; b=~0ULL; EXPECT_TRUE(safe_mod(NULL, a, b));
+  a=100ULL; b=0ULL; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10ULL; b=2ULL; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+int T_mod_sizet() {
+  int r=1;
+  size_t a, b;
+  a=0; b=SIZE_MAX; EXPECT_TRUE(safe_mod(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_mod(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_mod(NULL, a, b));
+  return r;
+}
+
+/***** DIV *****/
+int T_div_s8() {
+  int r=1;
+  int8_t a, b;
+  a=SCHAR_MIN; b=-1; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_s16() {
+  int r=1;
+  int16_t a, b;
+  a=SHRT_MIN; b=-1; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_s32() {
+  int r=1;
+  int32_t a, b;
+  a=INT_MIN; b=-1; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_s64() {
+  int r=1;
+  int64_t a, b;
+  a=SAFE_INT64_MIN; b=-1; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_long() {
+  int r=1;
+  long a, b;
+  a=LONG_MIN; b=-1; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+int T_div_longlong() {
+  int r=1;
+  long long a, b;
+  a=LLONG_MIN; b=-1LL; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=100LL; b=0LL; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10LL; b=2LL; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+int T_div_ssizet() {
+  int r=1;
+  ssize_t a, b;
+  a=SSIZE_MIN; b=-1; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_u8() {
+  int r=1;
+  uint8_t a, b;
+  a=0; b=UCHAR_MAX; EXPECT_TRUE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_u16() {
+  int r=1;
+  uint16_t a, b;
+  a=0; b=USHRT_MAX; EXPECT_TRUE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_u32() {
+  int r=1;
+  uint32_t a, b;
+  a=0; b=UINT_MAX; EXPECT_TRUE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_u64() {
+  int r=1;
+  uint64_t a, b;
+  a=0; b=SAFE_INT64_MAX; EXPECT_TRUE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_ulong() {
+  int r=1;
+  unsigned long a, b;
+  a=0; b=LONG_MAX; EXPECT_TRUE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_ulonglong() {
+  int r=1;
+  unsigned long long a, b;
+  a=0ULL; b=~0ULL; EXPECT_TRUE(safe_div(NULL, a, b));
+  a=100ULL; b=0ULL; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10ULL; b=2ULL; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_div_sizet() {
+  int r=1;
+  size_t a, b;
+  a=0; b=SIZE_MAX; EXPECT_TRUE(safe_div(NULL, a, b));
+  a=100; b=0; EXPECT_FALSE(safe_div(NULL, a, b));
+  a=10; b=2; EXPECT_TRUE(safe_div(NULL, a, b));
+  return r;
+}
+
+int T_magic_constants() {
+  int r=1;
+  EXPECT_TRUE(__sio(m)(smin)(((int8_t)0)) == SCHAR_MIN);
+  EXPECT_TRUE(__sio(m)(smax)(((int8_t)0)) == SCHAR_MAX);
+  EXPECT_TRUE(__sio(m)(umax)(((uint8_t)0)) == UCHAR_MAX);
+
+  EXPECT_TRUE(__sio(m)(smin)(((int16_t)0)) == SHRT_MIN);
+  EXPECT_TRUE(__sio(m)(smax)(((int16_t)0)) == SHRT_MAX);
+  EXPECT_TRUE(__sio(m)(umax)(((uint16_t)0)) == USHRT_MAX);
+
+  EXPECT_TRUE(__sio(m)(smin)(((int32_t)0)) == INT_MIN);
+  EXPECT_TRUE(__sio(m)(smax)(((int32_t)0)) == INT_MAX);
+  EXPECT_TRUE(__sio(m)(umax)(((uint32_t)0)) == UINT_MAX);
+
+  EXPECT_TRUE(__sio(m)(smin)(((int64_t)0)) == SAFE_INT64_MIN);
+  EXPECT_TRUE(__sio(m)(smax)(((int64_t)0)) == SAFE_INT64_MAX);
+  EXPECT_TRUE(__sio(m)(umax)(((uint64_t)0)) == SAFE_UINT64_MAX);
+
+  EXPECT_TRUE(__sio(m)(smin)(((ssize_t)0)) == SSIZE_MIN);
+  EXPECT_TRUE(__sio(m)(smax)(((ssize_t)0)) == SSIZE_MAX);
+  EXPECT_TRUE(__sio(m)(umax)(((size_t)0)) == SIZE_MAX);
+
+  EXPECT_TRUE(__sio(m)(smin)(((long)0)) == LONG_MIN);
+  EXPECT_TRUE(__sio(m)(smax)(((long)0)) == LONG_MAX);
+  EXPECT_TRUE(__sio(m)(umax)(((unsigned long)0)) == ULONG_MAX);
+
+  EXPECT_TRUE(__sio(m)(smin)(((long long)0)) == LLONG_MIN);
+  EXPECT_TRUE(__sio(m)(smax)(((long long)0)) == LLONG_MAX);
+  EXPECT_TRUE(__sio(m)(umax)(((unsigned long long)0)) == ULLONG_MAX);
+
+  return r;
+}
+
+
+
+
+int main(int argc, char **argv) {
+  /* test inlines */
+  int tests = 0, succ = 0, fail = 0;
+  tests++; if (T_div_s8())  succ++; else fail++;
+  tests++; if (T_div_s16()) succ++; else fail++;
+  tests++; if (T_div_s32()) succ++; else fail++;
+  tests++; if (T_div_s64()) succ++; else fail++;
+  tests++; if (T_div_long()) succ++; else fail++;
+  tests++; if (T_div_longlong()) succ++; else fail++;
+  tests++; if (T_div_ssizet()) succ++; else fail++;
+  tests++; if (T_div_u8())  succ++; else fail++;
+  tests++; if (T_div_u16()) succ++; else fail++;
+  tests++; if (T_div_u32()) succ++; else fail++;
+  tests++; if (T_div_u64()) succ++; else fail++;
+  tests++; if (T_div_ulong()) succ++; else fail++;
+  tests++; if (T_div_ulonglong()) succ++; else fail++;
+  tests++; if (T_div_sizet()) succ++; else fail++;
+
+  tests++; if (T_mod_s8())  succ++; else fail++;
+  tests++; if (T_mod_s16()) succ++; else fail++;
+  tests++; if (T_mod_s32()) succ++; else fail++;
+  tests++; if (T_mod_s64()) succ++; else fail++;
+  tests++; if (T_mod_long()) succ++; else fail++;
+  tests++; if (T_mod_longlong()) succ++; else fail++;
+  tests++; if (T_mod_ssizet()) succ++; else fail++;
+  tests++; if (T_mod_u8())  succ++; else fail++;
+  tests++; if (T_mod_u16()) succ++; else fail++;
+  tests++; if (T_mod_u32()) succ++; else fail++;
+  tests++; if (T_mod_u64()) succ++; else fail++;
+  tests++; if (T_mod_ulong()) succ++; else fail++;
+  tests++; if (T_mod_ulonglong()) succ++; else fail++;
+  tests++; if (T_mod_sizet()) succ++; else fail++;
+
+  tests++; if (T_mul_s8())  succ++; else fail++;
+  tests++; if (T_mul_s16()) succ++; else fail++;
+  tests++; if (T_mul_s32()) succ++; else fail++;
+  tests++; if (T_mul_s64()) succ++; else fail++;
+  tests++; if (T_mul_long()) succ++; else fail++;
+  tests++; if (T_mul_longlong()) succ++; else fail++;
+  tests++; if (T_mul_ssizet()) succ++; else fail++;
+  tests++; if (T_mul_u8())  succ++; else fail++;
+  tests++; if (T_mul_u16()) succ++; else fail++;
+  tests++; if (T_mul_u32()) succ++; else fail++;
+  tests++; if (T_mul_u64()) succ++; else fail++;
+  tests++; if (T_mul_ulong()) succ++; else fail++;
+  tests++; if (T_mul_ulonglong()) succ++; else fail++;
+  tests++; if (T_mul_sizet()) succ++; else fail++;
+
+  tests++; if (T_sub_s8())  succ++; else fail++;
+  tests++; if (T_sub_s16()) succ++; else fail++;
+  tests++; if (T_sub_s32()) succ++; else fail++;
+  tests++; if (T_sub_s64()) succ++; else fail++;
+  tests++; if (T_sub_long()) succ++; else fail++;
+  tests++; if (T_sub_longlong()) succ++; else fail++;
+  tests++; if (T_sub_ssizet()) succ++; else fail++;
+  tests++; if (T_sub_u8())  succ++; else fail++;
+  tests++; if (T_sub_u16()) succ++; else fail++;
+  tests++; if (T_sub_u32()) succ++; else fail++;
+  tests++; if (T_sub_u64()) succ++; else fail++;
+  tests++; if (T_sub_ulong()) succ++; else fail++;
+  tests++; if (T_sub_ulonglong()) succ++; else fail++;
+  tests++; if (T_sub_sizet()) succ++; else fail++;
+
+  tests++; if (T_add_s8())  succ++; else fail++;
+  tests++; if (T_add_s16()) succ++; else fail++;
+  tests++; if (T_add_s32()) succ++; else fail++;
+  tests++; if (T_add_s64()) succ++; else fail++;
+  tests++; if (T_add_long()) succ++; else fail++;
+  tests++; if (T_add_longlong()) succ++; else fail++;
+  tests++; if (T_add_ssizet()) succ++; else fail++;
+  tests++; if (T_add_u8())  succ++; else fail++;
+  tests++; if (T_add_u16()) succ++; else fail++;
+  tests++; if (T_add_u32()) succ++; else fail++;
+  tests++; if (T_add_u64()) succ++; else fail++;
+  tests++; if (T_add_ulong()) succ++; else fail++;
+  tests++; if (T_add_ulonglong()) succ++; else fail++;
+  tests++; if (T_add_sizet()) succ++; else fail++;
+  tests++; if (T_add_mixed()) succ++; else fail++;
+  tests++; if (T_add_increment()) succ++; else fail++;
+
+  tests++; if (T_magic_constants()) succ++; else fail++;
+
+  printf("%d/%d expects succeeded (%d failures)\n",
+         expect_succ, expect, expect_fail);
+  printf("%d/%d tests succeeded (%d failures)\n", succ, tests, fail);
+  /* TODO: Add tests for safe_iopf when upgraded */
+  return fail;
+}
+#endif