Commit 3186141
Changed files (5)
testing
tests
util
testing/tests/001_safemath.c
@@ -124,6 +124,121 @@ void entry(void) {
assert( S_FAILED( s16_add( s16_MIN, -1, (s16*)&res )));
assert( S_FAILED( s8_add( s8_MIN, -1, (s8 *)&res )));
+ /* Basic multiplication */
+ assert( S_OK( u64_mul( 3, 2, &res ))); assert( res == 6 );
+ assert( S_OK( u32_mul( 3, 2, (u32*)&res ))); assert( (u32)res == 6 );
+ assert( S_OK( u16_mul( 3, 2, (u16*)&res ))); assert( (u16)res == 6 );
+ assert( S_OK( u8_mul( 3, 2, (u8 *)&res ))); assert( ( u8)res == 6 );
+
+ assert( S_OK( s64_mul( 3, 2, (s64*)&res ))); assert( (s64)res == 6 );
+ assert( S_OK( s32_mul( 3, 2, (s32*)&res ))); assert( (s32)res == 6 );
+ assert( S_OK( s16_mul( 3, 2, (s16*)&res ))); assert( (s16)res == 6 );
+ assert( S_OK( s8_mul( 3, 2, (s8 *)&res ))); assert( ( s8)res == 6 );
+
+ assert( S_OK( s64_mul( -3, 2, (s64*)&res ))); assert( (s64)res == -6 );
+ assert( S_OK( s32_mul( -3, 2, (s32*)&res ))); assert( (s32)res == -6 );
+ assert( S_OK( s16_mul( -3, 2, (s16*)&res ))); assert( (s16)res == -6 );
+ assert( S_OK( s8_mul( -3, 2, (s8 *)&res ))); assert( ( s8)res == -6 );
+
+ /* Zero */
+ assert( S_OK( u64_mul( u64_MAX, 0, &res ))); assert( res == 0 );
+ assert( S_OK( u32_mul( u32_MAX, 0, (u32*)&res ))); assert( res == 0 );
+ assert( S_OK( u16_mul( u16_MAX, 0, (u16*)&res ))); assert( res == 0 );
+ assert( S_OK( u8_mul( u8_MAX, 0, (u8 *)&res ))); assert( res == 0 );
+
+ assert( S_OK( s64_mul( s64_MAX, 0, (s64*)&res ))); assert( res == 0 );
+ assert( S_OK( s32_mul( s32_MAX, 0, (s32*)&res ))); assert( res == 0 );
+ assert( S_OK( s16_mul( s16_MAX, 0, (s16*)&res ))); assert( res == 0 );
+ assert( S_OK( s8_mul( s8_MAX, 0, (s8 *)&res ))); assert( res == 0 );
+
+ assert( S_OK( u64_mul( 0, u64_MAX, &res ))); assert( res == 0 );
+ assert( S_OK( u32_mul( 0, u32_MAX, (u32*)&res ))); assert( (u32)res == 0 );
+ assert( S_OK( u16_mul( 0, u16_MAX, (u16*)&res ))); assert( (u16)res == 0 );
+ assert( S_OK( u8_mul( 0, u8_MAX, (u8 *)&res ))); assert( ( u8)res == 0 );
+
+ assert( S_OK( s64_mul( 0, s64_MIN, (s64*)&res ))); assert( (s64)res == 0 );
+ assert( S_OK( s32_mul( 0, s32_MIN, (s32*)&res ))); assert( (s32)res == 0 );
+ assert( S_OK( s16_mul( 0, s16_MIN, (s16*)&res ))); assert( (s16)res == 0 );
+ assert( S_OK( s8_mul( 0, s8_MIN, (s8 *)&res ))); assert( ( s8)res == 0 );
+
+ /* Overflow */
+ assert( S_FAILED( u64_mul( u64_MAX, 2, &res )));
+ assert( S_FAILED( u32_mul( u32_MAX, 2, (u32*)&res )));
+ assert( S_FAILED( u16_mul( u16_MAX, 2, (u16*)&res )));
+ assert( S_FAILED( u8_mul( u8_MAX, 2, (u8 *)&res )));
+
+ assert( S_FAILED( s64_mul( s64_MIN, 2, (s64*)&res )));
+ assert( S_FAILED( s32_mul( s32_MIN, 2, (s32*)&res )));
+ assert( S_FAILED( s16_mul( s16_MIN, 2, (s16*)&res )));
+ assert( S_FAILED( s8_mul( s8_MIN, 2, (s8 *)&res )));
+
+ assert( S_FAILED( s64_mul( s64_MAX, 2, (s64*)&res )));
+ assert( S_FAILED( s32_mul( s32_MAX, 2, (s32*)&res )));
+ assert( S_FAILED( s16_mul( s16_MAX, 2, (s16*)&res )));
+ assert( S_FAILED( s8_mul( s8_MAX, 2, (s8 *)&res )));
+
+ assert( S_FAILED( s64_mul( s64_MIN, -1, (s64*)&res )));
+ assert( S_FAILED( s32_mul( s32_MIN, -1, (s32*)&res )));
+ assert( S_FAILED( s16_mul( s16_MIN, -1, (s16*)&res )));
+ assert( S_FAILED( s8_mul( s8_MIN, -1, (s8 *)&res )));
+
+ assert( S_FAILED( s64_mul( s64_MIN/2, -2, (s64*)&res )));
+ assert( S_FAILED( s32_mul( s32_MIN/2, -2, (s32*)&res )));
+ assert( S_FAILED( s16_mul( s16_MIN/2, -2, (s16*)&res )));
+ assert( S_FAILED( s8_mul( s8_MIN/2, -2, (s8 *)&res )));
+
+ /* Signed-specific */
+ assert( S_OK( s64_mul( s64_MAX, -1, (s64*)&res )));
+ assert( S_OK( s32_mul( s32_MAX, -1, (s32*)&res )));
+ assert( S_OK( s16_mul( s16_MAX, -1, (s16*)&res )));
+ assert( S_OK( s8_mul( s8_MAX, -1, (s8 *)&res )));
+
+ assert( S_OK( s64_mul( s64_MIN + 1, -1, (s64*)&res ))); assert( (s64)res == s64_MAX );
+ assert( S_OK( s32_mul( s32_MIN + 1, -1, (s32*)&res ))); assert( (s32)res == s32_MAX );
+ assert( S_OK( s16_mul( s16_MIN + 1, -1, (s16*)&res ))); assert( (s16)res == s16_MAX );
+ assert( S_OK( s8_mul( s8_MIN + 1, -1, (s8 *)&res ))); assert( ( s8)res == s8_MAX );
+
+ assert( S_OK( s64_mul( s64_MIN / -2, -2, (s64*)&res ))); assert( (s64)res == s64_MIN );
+ assert( S_OK( s32_mul( s32_MIN / -2, -2, (s32*)&res ))); assert( (s32)res == s32_MIN );
+ assert( S_OK( s16_mul( s16_MIN / -2, -2, (s16*)&res ))); assert( (s16)res == s16_MIN );
+ assert( S_OK( s8_mul( s8_MIN / -2, -2, (s8 *)&res ))); assert( ( s8)res == s8_MIN );
+
+ assert( S_OK( s64_mul( s64_MIN / 2 + 1, -2, (s64*)&res ))); assert( (s64)res == s64_MAX - 1 );
+ assert( S_OK( s32_mul( s32_MIN / 2 + 1, -2, (s32*)&res ))); assert( (s32)res == s32_MAX - 1 );
+ assert( S_OK( s16_mul( s16_MIN / 2 + 1, -2, (s16*)&res ))); assert( (s16)res == s16_MAX - 1 );
+ assert( S_OK( s8_mul( s8_MIN / 2 + 1, -2, (s8 *)&res ))); assert( ( s8)res == s8_MAX - 1 );
+
+
+ /* Catch potential off-by-one errors */
+ assert( S_OK( u64_mul( u64_MAX/2, 2, &res ))); assert( res == u64_MAX - 1 );
+ assert( S_OK( u32_mul( u32_MAX/2, 2, (u32*)&res ))); assert( (u32)res == u32_MAX - 1 );
+ assert( S_OK( u16_mul( u16_MAX/2, 2, (u16*)&res ))); assert( (u16)res == u16_MAX - 1);
+ assert( S_OK( u8_mul( u8_MAX/2, 2, (u8 *)&res ))); assert( ( u8)res == u8_MAX - 1);
+
+ assert( S_FAILED( u64_mul( u64_MAX / 2 + 1, 2, &res )));
+ assert( S_FAILED( u32_mul( u32_MAX / 2 + 1, 2, (u32*)&res )));
+ assert( S_FAILED( u16_mul( u16_MAX / 2 + 1, 2, (u16*)&res )));
+ assert( S_FAILED( u8_mul( u8_MAX / 2 + 1, 2, (u8 *)&res )));
+
+ assert( S_OK( s64_mul( s64_MAX/2, 2, (s64*)&res ))); assert( (s64)res == s64_MAX - 1 );
+ assert( S_OK( s32_mul( s32_MAX/2, 2, (s32*)&res ))); assert( (s32)res == s32_MAX - 1 );
+ assert( S_OK( s16_mul( s16_MAX/2, 2, (s16*)&res ))); assert( (s16)res == s16_MAX - 1 );
+ assert( S_OK( s8_mul( s8_MAX/2, 2, (s8 *)&res ))); assert( ( s8)res == s8_MAX - 1 );
+
+ assert( S_OK( s64_mul( s64_MIN/2, 2, (s64*)&res ))); assert( (s64)res == s64_MIN );
+ assert( S_OK( s32_mul( s32_MIN/2, 2, (s32*)&res ))); assert( (s32)res == s32_MIN );
+ assert( S_OK( s16_mul( s16_MIN/2, 2, (s16*)&res ))); assert( (s16)res == s16_MIN );
+ assert( S_OK( s8_mul( s8_MIN/2, 2, (s8 *)&res ))); assert( ( s8)res == s8_MIN );
+
+ assert( S_FAILED( s64_mul( s64_MAX/2 + 1, 2, (s64*)&res )));
+ assert( S_FAILED( s32_mul( s32_MAX/2 + 1, 2, (s32*)&res )));
+ assert( S_FAILED( s16_mul( s16_MAX/2 + 1, 2, (s16*)&res )));
+ assert( S_FAILED( s8_mul( s8_MAX/2 + 1, 2, (s8 *)&res )));
+
+ assert( S_FAILED( s64_mul( s64_MIN/2 - 1, 2, (s64*)&res )));
+ assert( S_FAILED( s32_mul( s32_MIN/2 - 1, 2, (s32*)&res )));
+ assert( S_FAILED( s16_mul( s16_MIN/2 - 1, 2, (s16*)&res )));
+ assert( S_FAILED( s8_mul( s8_MIN/2 - 1, 2, (s8 *)&res )));
terminate(0);
}
util/mathops/max.h
@@ -1,5 +1,5 @@
-#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_MIN_INCLUDED
-#define NOTLIBC_HEADER_UTIL_MATHOPS_MIN_INCLUDED
+#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_MAX_INCLUDED
+#define NOTLIBC_HEADER_UTIL_MATHOPS_MAX_INCLUDED
#include "platform/common/types.h"
util/safemath.h
@@ -7,20 +7,34 @@
/* Ensure limit sanity - at least for unsigned */
-ASSERT(u64_MAX == 0xffffffffffffffff );
-ASSERT(u32_MAX == 0xffffffff );
-ASSERT(u16_MAX == 0xffff );
-ASSERT(u8_MAX == 0xff );
+ASSERT( u64_MAX == 0xffffffffffffffff );
+ASSERT( u32_MAX == 0xffffffff );
+ASSERT( u16_MAX == 0xffff );
+ASSERT( u8_MAX == 0xff );
static inline Status u8_add(u8 n1, u8 n2, u8 *out);
static inline Status u16_add(u16 n1, u16 n2, u16 *out);
static inline Status u32_add(u32 n1, u32 n2, u32 *out);
static inline Status u64_add(u64 n1, u64 n2, u64 *out);
-static inline Status usize_add(u64 n1, u64 n2, u64 *out) {
+
+static inline Status u8_mul(u8 n1, u8 n2, u8 *out);
+static inline Status u16_mul(u16 n1, u16 n2, u16 *out);
+static inline Status u32_mul(u32 n1, u32 n2, u32 *out);
+static inline Status u64_mul(u64 n1, u64 n2, u64 *out);
+
+static inline Status usize_add(usize n1, usize n2, usize *out) {
+ #if ARCH == ARCH_X86_64
+ return u64_add( n1, n2, out );
+ #elif ARCH == ARCH_I386
+ return u32_add( n1, n2, out );
+ #endif
+}
+
+static inline Status usize_mul(usize n1, usize n2, usize *out) {
#if ARCH == ARCH_X86_64
- return u64_add( n1, n2, out );
+ return u64_mul( n1, n2, out );
#elif ARCH == ARCH_I386
- return u32_add( n1, n2, out );
+ return u32_mul( n1, n2, out );
#endif
}
@@ -31,7 +45,7 @@ static inline Status s64_add(s64 n1, s64 n2, s64 *out);
#ifdef NOTLIBC_IMPLEMENT
- #if COMPILER == COMPILER_GCC || COPMILER == COMPILER_CLANG
+ #if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
#include "./safemath_gcclike.h"
#else
#include "./safemath_generic.h"
util/safemath_gcclike.h
@@ -1,7 +1,7 @@
#ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_GCCLIKE_INCLUDED
#define NOTLIBC_HEADER_UTIL_SAFEMATH_GCCLIKE_INCLUDED
-#include "datatypes/common.h"
+#include "datatypes/error.h"
/* Unsigned addition */
@@ -125,4 +125,62 @@ static inline Status s8_sub( s8 n1, s8 n2, s8 *out ) {
return S_SUCCESS;
}
+/* Unsigned multiplication */
+
+static inline Status u64_mul( u64 n1, u64 n2, u64 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
+static inline Status u32_mul( u32 n1, u32 n2, u32 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
+static inline Status u16_mul( u16 n1, u16 n2, u16 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
+static inline Status u8_mul( u8 n1, u8 n2, u8 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
+static inline Status s64_mul( s64 n1, s64 n2, s64 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
+static inline Status s32_mul( s32 n1, s32 n2, s32 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
+static inline Status s16_mul( s16 n1, s16 n2, s16 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
+static inline Status s8_mul( s8 n1, s8 n2, s8 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+}
+
#endif
util/safemath_generic.h
@@ -141,4 +141,90 @@ static inline Status s8_sub( s8 n1, s8 n2, s8 *out ) {
return S_SUCCESS;
}
+/* Unsigned multiplication */
+static inline Status u64_mul( u64 n1, u64 n2, u64 *out ) {
+ if( n1 && n2 > (u64_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+}
+
+static inline Status u32_mul( u32 n1, u32 n2, u32 *out ) {
+ if( n1 && n2 > (u32_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+}
+
+static inline Status u16_mul( u16 n1, u16 n2, u16 *out ) {
+ if( n1 && n2 > (u16_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+}
+
+static inline Status u8_mul( u8 n1, u8 n2, u8 *out ) {
+ if( n1 && n2 > (u8_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+}
+
+/* Signed multiplication */
+static inline Status s64_mul( s64 n1, s64 n2, s64 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s64_MIN/n2 && n1 <= s64_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s64_MAX ) ||
+ ( n2 < -1 && n1 >= s64_MAX/n2 && n1 <= s64_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+}
+
+static inline Status s32_mul( s32 n1, s32 n2, s32 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s32_MIN/n2 && n1 <= s32_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s32_MAX ) ||
+ ( n2 < -1 && n1 >= s32_MAX/n2 && n1 <= s32_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+}
+
+static inline Status s16_mul( s16 n1, s16 n2, s16 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s16_MIN/n2 && n1 <= s16_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s16_MAX ) ||
+ ( n2 < -1 && n1 >= s16_MAX/n2 && n1 <= s16_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+}
+
+static inline Status s8_mul( s8 n1, s8 n2, s8 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s8_MIN/n2 && n1 <= s8_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s8_MAX ) ||
+ ( n2 < -1 && n1 >= s8_MAX/n2 && n1 <= s8_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+}
+
#endif