/*-
* MirBSD sanitisation attempt for C integer madness
*
* Published under Ⓕ CC0
*/
#ifndef SYSKERN_MBSDINT_H
#define SYSKERN_MBSDINT_H "$MirOS: src/bin/mksh/mbsdint.h,v 1.2 2022/01/28 03:49:12 tg Exp $"
/* if you have <sys/types.h> and/or <stdint.h>, include them before this */
#if !defined(_KERNEL) && !defined(_STANDALONE)
#include <limits.h>
#include <stddef.h>
#else
#include <sys/cdefs.h>
#include <sys/limits.h>
#include <sys/stddef.h>
#endif
/* should be in <sys/cdefs.h> via <limits.h> */
#ifndef __predict_true
#if defined(__GNUC__) && (__GNUC__ >= 3) /* 2.96, but keep it simple here */
#define __predict_true(exp) __builtin_expect(!!(exp), 1)
#define __predict_false(exp) __builtin_expect(!!(exp), 0)
#else
#define __predict_true(exp) (!!(exp))
#define __predict_false(exp) (!!(exp))
#endif /* !GCC 3.x */
#endif /* ndef(__predict_true) */
#if !defined(SIZE_MAX) && defined(SIZE_T_MAX)
#define SIZE_MAX SIZE_T_MAX
#endif
/* compile-time assertions: mbiCTAS(srcf_c) { … }; */
#define mbiCTAS(name) struct ctassert_ ## name
#define mbiCTA(name,cond) char cta_ ## name [(cond) ? 1 : -1]
/* special CTAs */
#define mbiCTA_TYPE_NOTF(type) char ctati_ ## type [((type)0.5 == 0) ? 1 : -1]
/* largest integer */
#if defined(INTMAX_MIN)
#define mbiHUGE_S intmax_t
#define mbiHUGE_MIN INTMAX_MIN
#define mbiHUGE_MAX INTMAX_MAX
#define mbiHUGE_U uintmax_t
#define mbiHUGE_UMAX UINTMAX_MAX
#elif defined(LLONG_MIN)
#define mbiHUGE_S long long
#define mbiHUGE_MIN LLONG_MIN
#define mbiHUGE_MAX LLONG_MAX
#define mbiHUGE_U unsigned long long
#define mbiHUGE_UMAX ULLONG_MAX
#else
#define mbiHUGE_S long
#define mbiHUGE_MIN LONG_MIN
#define mbiHUGE_MAX LONG_MAX
#define mbiHUGE_U unsigned long
#define mbiHUGE_UMAX ULONG_MAX
#endif
/* kinds of types */
/* runtime only, but see mbiCTA_TYPE_NOTF */
#define mbiTYPE_ISF(type) ((double)0.5 == (double)(type)0.5)
/* compile-time and runtime */
#define mbiTYPE_ISU(type) ((type)-1 > 0)
/* limits of types */
#define mbiTYPE_UMAX(type) ((type)~(type)0)
#define mbiTYPE_UBITS(type) mbiMASK_BITS(mbiTYPE_UMAX(type))
/* calculation by Hallvard B Furuseth (from comp.lang.c), up to 2039 bits */
#define mbiMASK_BITS(maxv) ((unsigned int)((maxv) / ((maxv) % 255 + 1) / \
255 % 255 * 8 + 7 - 86 / ((maxv) % 255 + 12)))
/* ensure v is a positive (2ⁿ-1) number (n>0), up to 279 bits */
#define mbiMASK_CHK(v) ((v) > 0 ? mbi_maskchk31_1((v)) : 0)
#define mbi_maskchks(v,m,o,n) (v <= m ? o : ((v & m) == m) && n)
#define mbi_maskchk31s(v,n) mbi_maskchks(v, 0x7FFFFFFFUL, \
mbi_maskchk16(v), n)
#define mbi_maskchk31_1(v) mbi_maskchk31s(v, mbi_maskchk31_2(v >> 31))
#define mbi_maskchk31_2(v) mbi_maskchk31s(v, mbi_maskchk31_3(v >> 31))
#define mbi_maskchk31_3(v) mbi_maskchk31s(v, mbi_maskchk31_4(v >> 31))
#define mbi_maskchk31_4(v) mbi_maskchk31s(v, mbi_maskchk31_5(v >> 31))
#define mbi_maskchk31_5(v) mbi_maskchk31s(v, mbi_maskchk31_6(v >> 31))
#define mbi_maskchk31_6(v) mbi_maskchk31s(v, mbi_maskchk31_7(v >> 31))
#define mbi_maskchk31_7(v) mbi_maskchk31s(v, mbi_maskchk31_8(v >> 31))
#define mbi_maskchk31_8(v) mbi_maskchk31s(v, mbi_maskchk31_9(v >> 31))
#define mbi_maskchk31_9(v) (v <= 0x7FFFFFFFUL && mbi_maskchk16(v))
#define mbi_maskchk16(v) mbi_maskchks(v, 0xFFFFU, \
mbi_maskchk8(v), mbi_maskchk8(v >> 16))
#define mbi_maskchk8(v) mbi_maskchks(v, 0xFFU, \
mbi_maskchk4(v), mbi_maskchk4(v >> 8))
#define mbi_maskchk4(v) mbi_maskchks(v, 0xFU, \
mbi_maskchkF(v), mbi_maskchkF(v >> 4))
#define mbi_maskchkF(v) (v == 0xF || v == 7 || v == 3 || v == 1 || !v)
/* compile-time assertions for mbsdint.h */
mbiCTAS(mbsdint_h) {
/* compiler (in)sanity, from autoconf */
#define mbiCTf(x) 'x'
mbiCTA(xlc6, mbiCTf(a) == 'x');
#undef mbiCTf
mbiCTA(osf4, '\x00' == 0);
/* C types */
mbiCTA(basic_char,
sizeof(char) == 1 && (CHAR_BIT) >= 7 && (CHAR_BIT) < 2040 &&
mbiTYPE_UMAX(unsigned char) == (UCHAR_MAX) &&
sizeof(signed char) == 1 &&
sizeof(unsigned char) == 1 &&
mbiMASK_CHK(SCHAR_MAX) && mbiMASK_CHK(UCHAR_MAX) &&
((SCHAR_MIN) == -(SCHAR_MAX) || (SCHAR_MIN) == -(SCHAR_MAX)-1) &&
mbiTYPE_UBITS(unsigned char) == (unsigned int)(CHAR_BIT));
mbiCTA(basic_short,
mbiTYPE_UMAX(unsigned short) == (USHRT_MAX) &&
sizeof(short) <= (279 / CHAR_BIT) &&
sizeof(unsigned short) <= (279 / CHAR_BIT) &&
mbiMASK_CHK(SHRT_MAX) && mbiMASK_CHK(USHRT_MAX) &&
((SHRT_MIN) == -(SHRT_MAX) || (SHRT_MIN) == -(SHRT_MAX)-1) &&
sizeof(short) >= sizeof(signed char) &&
sizeof(unsigned short) >= sizeof(unsigned char) &&
sizeof(short) == sizeof(unsigned short));
mbiCTA(basic_int,
mbiTYPE_UMAX(unsigned int) == (UINT_MAX) &&
sizeof(int) <= (279 / CHAR_BIT) &&
sizeof(unsigned int) <= (279 / CHAR_BIT) &&
mbiMASK_CHK(INT_MAX) && mbiMASK_CHK(UINT_MAX) &&
((INT_MIN) == -(INT_MAX) || (INT_MIN) == -(INT_MAX)-1) &&
sizeof(int) >= sizeof(short) &&
sizeof(unsigned int) >= sizeof(unsigned short) &&
sizeof(int) == sizeof(unsigned int));
mbiCTA(basic_long,
mbiTYPE_UMAX(unsigned long) == (ULONG_MAX) &&
sizeof(long) <= (279 / CHAR_BIT) &&
sizeof(unsigned long) <= (279 / CHAR_BIT) &&
mbiMASK_CHK(LONG_MAX) && mbiMASK_CHK(ULONG_MAX) &&
((LONG_MIN) == -(LONG_MAX) || (LONG_MIN) == -(LONG_MAX)-1) &&
sizeof(long) >= sizeof(int) &&
sizeof(unsigned long) >= sizeof(unsigned int) &&
sizeof(long) == sizeof(unsigned long));
#ifdef LLONG_MIN
mbiCTA(basic_quad,
mbiTYPE_UMAX(unsigned long long) == (ULLONG_MAX) &&
sizeof(long long) <= (279 / CHAR_BIT) &&
sizeof(unsigned long long) <= (279 / CHAR_BIT) &&
mbiMASK_CHK(LLONG_MAX) && mbiMASK_CHK(ULLONG_MAX) &&
((LLONG_MIN) == -(LLONG_MAX) || (LLONG_MIN) == -(LLONG_MAX)-1) &&
sizeof(long long) >= sizeof(long) &&
sizeof(unsigned long long) >= sizeof(unsigned long) &&
sizeof(long long) == sizeof(unsigned long long));
#endif
#ifdef INTMAX_MIN
mbiCTA(basic_imax,
mbiTYPE_UMAX(uintmax_t) == (UINTMAX_MAX) &&
sizeof(intmax_t) <= (279 / CHAR_BIT) &&
sizeof(uintmax_t) <= (279 / CHAR_BIT) &&
mbiMASK_CHK(INTMAX_MAX) && mbiMASK_CHK(UINTMAX_MAX) &&
((INTMAX_MIN) == -(INTMAX_MAX) || (INTMAX_MIN) == -(INTMAX_MAX)-1) &&
#ifdef LLONG_MIN
sizeof(intmax_t) >= sizeof(long long) &&
sizeof(uintmax_t) >= sizeof(unsigned long long) &&
#else
sizeof(intmax_t) >= sizeof(long) &&
sizeof(uintmax_t) >= sizeof(unsigned long) &&
#endif
sizeof(intmax_t) == sizeof(uintmax_t));
#endif
/* size_t is C but ssize_t is POSIX */
mbiCTA_TYPE_NOTF(size_t);
mbiCTA(basic_sizet,
sizeof(size_t) >= sizeof(unsigned int) &&
sizeof(size_t) <= sizeof(mbiHUGE_U) &&
mbiTYPE_ISU(size_t) &&
#ifdef SIZE_MAX
mbiMASK_CHK(SIZE_MAX) &&
mbiMASK_BITS(SIZE_MAX) <= mbiTYPE_UBITS(size_t) &&
((SIZE_MAX) == (mbiHUGE_U)(size_t)(SIZE_MAX)) &&
#endif
mbiTYPE_UBITS(size_t) <= mbiMASK_BITS(mbiHUGE_UMAX));
mbiCTA_TYPE_NOTF(ptrdiff_t);
mbiCTA(basic_ptrdifft,
sizeof(ptrdiff_t) >= sizeof(int) &&
sizeof(ptrdiff_t) <= sizeof(mbiHUGE_S) &&
!mbiTYPE_ISU(ptrdiff_t) &&
#ifdef PTRDIFF_MAX
mbiMASK_CHK(PTRDIFF_MAX) &&
((PTRDIFF_MAX) == (mbiHUGE_S)(ptrdiff_t)(PTRDIFF_MAX)) &&
#endif
1);
/* UGH! off_t is POSIX, with no _MIN/_MAX constants… WTF‽ */
#ifdef SSIZE_MAX
mbiCTA_TYPE_NOTF(ssize_t);
mbiCTA(basic_ssizet,
sizeof(ssize_t) == sizeof(size_t) &&
!mbiTYPE_ISU(ssize_t) &&
mbiMASK_CHK(SSIZE_MAX) &&
((SSIZE_MAX) == (mbiHUGE_S)(ssize_t)(SSIZE_MAX)) &&
#ifdef SIZE_MAX
mbiMASK_BITS(SSIZE_MAX) <= mbiMASK_BITS(SIZE_MAX) &&
#endif
mbiMASK_BITS(SSIZE_MAX) < mbiTYPE_UBITS(size_t));
#endif
/* C99 §6.2.6.2(1, 2, 6) permits M ≤ N, but M < N is normally desired */
/* here require signed/unsigned types to have same width (M=N-1) */
mbiCTA(vbits_char, mbiMASK_BITS(UCHAR_MAX) == mbiMASK_BITS(SCHAR_MAX) + 1U);
mbiCTA(vbits_short, mbiMASK_BITS(USHRT_MAX) == mbiMASK_BITS(SHRT_MAX) + 1U);
mbiCTA(vbits_int, mbiMASK_BITS(UINT_MAX) == mbiMASK_BITS(INT_MAX) + 1U);
mbiCTA(vbits_long, mbiMASK_BITS(ULONG_MAX) == mbiMASK_BITS(LONG_MAX) + 1U);
#ifdef LLONG_MIN
mbiCTA(vbits_quad, mbiMASK_BITS(ULLONG_MAX) == mbiMASK_BITS(LLONG_MAX) + 1U);
#endif
#ifdef INTMAX_MIN
mbiCTA(vbits_imax, mbiMASK_BITS(UINTMAX_MAX) == mbiMASK_BITS(INTMAX_MAX) + 1U);
#endif
/* require pointers and size_t to take up the same amount of space */
mbiCTA(sizet_voidptr, sizeof(size_t) == sizeof(void *));
mbiCTA(sizet_funcptr, sizeof(size_t) == sizeof(void (*)(void)));
#if 0 /* breaks on LLP64 (e.g. Windows/amd64) */
mbiCTA(sizet_inulong, sizeof(size_t) <= sizeof(long));
#endif
/* assume ptrdiff_t and (s)size_t will fit each other */
mbiCTA(sizet_ptrdiff, sizeof(size_t) == sizeof(ptrdiff_t));
};
/*
* calculations where the unsigned type is used as backing store,
* doing the two’s complement conversion manually (to avoid UB/IB);
* (M=N-1), see above, is required for these to work (symmetrically)
*
* ut = unsigned type (e.g. unsigned long); st = signed type (e.g. long)
* SM = signed max (e.g. LONG_MAX); v = value
* m = magnitude (≥ 0 value); vz = signbit (0:value; 1:-value)
* HM = half mask (e.g. (ut)0x7FFFUL); FM = full mask (e.g. (ut)0xFFFFUL)
*/
/* 1. casting between unsigned(two’s complement) and signed(native) */
#define mbiA_U2S(ut,st,SM,v) (((v) > (ut)(SM)) ? \
(st)(-(st)(~(v)) - (st)1) : \
(st)(v))
#define mbiA_S2U(ut,st,v) (((v) < 0) ? \
(ut)(~(ut)(-((v) + (st)1))) : \
(ut)(v))
/* 2. converting between signed(native) and signbit(vz) plus magnitude */
#define mbiA_VZM2S(ut,st,vz,m) (((vz) && (m) > 0) ? \
(st)(-(st)((m) - (ut)1) - (st)1) : \
(st)(m))
#define mbiA_S2VZ(v) ((v) < 0)
#define mbiA_S2M(ut,st,v) (((v) < 0) ? \
(ut)((ut)(-((v) + (st)1)) + (ut)1) : \
(ut)(v))
/* 3. masking arithmetics in possibly-longer type */
#define mbiMA_U2S(ut,st,FM,HM,v) \
(((ut)((v) & FM) > HM) ? \
(st)(-(st)(~(v) & HM) - (st)1) : \
(st)((v) & HM))
#define mbiMA_S2U(ut,st,FM,v) ((ut)(mbiA_S2U(ut, st, v) & FM))
#define mbiMA_VZM2S(ut,st,FM,HM,vz,m) \
(((vz) && (ut)((m) & FM) > 0) ? \
(st)(-(st)(((m) - (ut)1) & HM) - (st)1) : \
(st)((m) & HM))
#define mbiMA_S2VZ(v) ((v) < 0)
#define mbiMA_S2M(ut,st,HM,v) (((v) < 0) ? \
(ut)((ut)((-((v) + (st)1)) & HM) + (ut)1) : \
(ut)((ut)(v) & HM))
/*
* UB-safe overflow/underflow-checking integer arithmetics
*
* Before using, #define mbiCfail to the action that should be
* taken on check (e.g. "goto fail" or "return (0)"); make sure
* to #undef mbiCfail before the end of the function body though!
*
* There is IB on some signed operations, but that is only either
* the result (which is checked) is implementation-defined, thus
* safe, or an implementation-defined signal is raised, which is
* the caller’s problem ☻
*/
/* 1. for unsigned types checking afterwards is OK */
#define mbiCAUinc(vl) mbiCAUadd(vl, 1)
#define mbiCAUdec(vl) mbiCAUsub(vl, 1)
#define mbiCAUadd(vl,vr) do { \
(vl) += (vr); \
if (__predict_false((vl) < (vr))) \
mbiCfail; \
} while (/* CONSTCOND */ 0)
#define mbiCAUsub(vl,vr) do { \
if (__predict_false((vl) < (vr))) \
mbiCfail; \
(vl) -= (vr); \
} while (/* CONSTCOND */ 0)
#define mbiCAUmul(vl,vr) do { \
if (__predict_false((((vl) * (vr)) / (vr)) < (vl))) \
mbiCfail; \
(vl) *= (vr); \
} while (/* CONSTCOND */ 0)
/* 2. for signed types; lim is a prefix (e.g. SHRT) */
#define mbiCASinc(lim,vl) do { \
if (__predict_false((vl) == lim ## _MAX)) \
mbiCfail; \
++(vl); \
} while (/* CONSTCOND */ 0)
#define mbiCASdec(lim,vl) do { \
if (__predict_false((vl) == lim ## _MIN)) \
mbiCfail; \
--(vl); \
} while (/* CONSTCOND */ 0)
#define mbiCASadd(lim,vl,vr) do { \
if (__predict_false((vl) > (lim ## _MAX - (vr)))) \
mbiCfail; \
(vl) += (vr); \
} while (/* CONSTCOND */ 0)
#define mbiCASsub(lim,vl,vr) do { \
if (__predict_false((vl) < (lim ## _MIN + (vr)))) \
mbiCfail; \
(vl) -= (vr); \
} while (/* CONSTCOND */ 0)
#define mbiCASmul(lim,vl,vr) do { \
if (__predict_false((lim ## _MAX / (vr)) < (vl) || \
(lim ## _MIN / (vr)) > (vl))) \
mbiCfail; \
(vl) *= (vr); \
} while (/* CONSTCOND */ 0)
/* 3. signed narrowing assign; this is IB */
#define mbiCASlet(dsttype,vl,srctype,vr) do { \
(vl) = (dsttype)(vr); \
if (__predict_false((srctype)(vl) != (vr))) \
mbiCfail; \
} while (/* CONSTCOND */ 0)
/*
* calculations on manual two’s complement
*
* addition, subtraction and multiplication, bitwise and boolean
* operations, as well as equality comparisons can be done on the
* unsigned value; other comparisons must be done on the signed
* value and the other operations follow
*/
/* rotate and shift: pass *unsigned* values; shr shifts in vz bits */
#define mbiVAU_shift(ut,dst,vl,vr,rv) do { \
(dst) = (vr) & (mbiTYPE_UBITS(ut) - 1); \
(dst) = (dst) ? (rv) : (vl); \
} while (/* CONSTCOND */ 0)
#define mbiVAUrol(ut,dst,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \
((vl) << (dst)) | ((vl) >> (mbiTYPE_UBITS(ut) - (dst))))
#define mbiVAUror(ut,dst,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \
((vl) >> (dst)) | ((vl) << (mbiTYPE_UBITS(ut) - (dst))))
#define mbiVAUshl(ut,dst,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \
(vl) << (dst))
#define mbiVAUshr(ut,dst,vz,vl,vr) mbiVAU_shift(ut, dst, vl, vr, \
(vz) ? (ut)~((ut)~(vl) >> (dst)) : (vl) >> (dst))
#define mbiM_do(dst,FM,act) do { act; (dst) &= FM; } while (/* CONSTCOND */ 0)
#define mbiMVAUrol(ut,FM,dst,vl,vr) mbiM_do(dst, FM, mbiVAUrol(ut,dst,vl,vr))
#define mbiMVAUror(ut,FM,dst,vl,vr) mbiM_do(dst, FM, mbiVAUror(ut,dst,vl,vr))
#define mbiMVAUshl(ut,FM,dst,vl,vr) mbiM_do(dst, FM, mbiVAUshl(ut,dst,vl,vr))
#define mbiMVAUshr(ut,FM,dst,vz,vl,vr) \
mbiM_do(dst, FM, mbiVAUshr(ut,dst,vz,vl,vr))
/* division and remainder; pass *signed* values and unsigned result vars */
#define mbiVASdivrem(ut,st,udiv,urem,vl,vr) do { \
(udiv) = mbiA_S2M(ut, st, (vl)) / mbiA_S2M(ut, st, (vr)); \
if (mbiA_S2VZ(vl) ^ mbiA_S2VZ(vr)) \
(udiv) = -(udiv); \
(urem) = mbiA_S2U(ut, st, (vl)) - \
((udiv) * mbiA_S2U(ut, st, (vr))); \
} while (/* CONSTCOND */ 0)
#define mbiMVASdivrem(ut,st,FM,HM,udiv,urem,vl,vr) do { \
(udiv) = mbiMA_S2M(ut, st, HM, (vl)) / \
mbiMA_S2M(ut, st, HM, (vr)); \
if (mbiMA_S2VZ(vl) ^ mbiMA_S2VZ(vr)) \
(udiv) = -(udiv); \
(urem) = mbiA_S2U(ut, st, (vl)) - \
((udiv) * mbiA_S2U(ut, st, (vr))); \
(udiv) &= FM; \
(urem) &= FM; \
} while (/* CONSTCOND */ 0)
#endif /* !SYSKERN_MBSDINT_H */