/usr/include/pike7.8/pike/bignum.h is in pike7.8-dev 7.8.866-8.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | /*
|| This file is part of Pike. For copyright information see COPYRIGHT.
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
|| for more information.
|| $Id: 2bda533ae0fe6f04bb3735e9cb03687070c35a83 $
*/
#ifndef BIGNUM_H
#define BIGNUM_H
#include "global.h"
#include "pike_int_types.h"
/* Note: These functions assume some properties of the CPU. */
#define INT_TYPE_SIGN(x) ((x) < 0)
/*
* Arithmetic operations which try to be standard compliant when checking for overflow.
* The first set of functions uses a second larger integer type to perform computations.
* The second uses manual multiplication for unsigned multiply or checks for overflow
* as recommended in
* https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
* When using clang with builtin support for checking arithmetic overflow, those builtins will
* be used.
* These functions will also detect and try to avoid undefined behavior, e.g. shifts of
* negative integers.
*
* The family of DO_*_OVERFLOW functions sets the result only if no overflow occured.
*/
#define GENERIC_OVERFLOW_CHECKS(type) \
static INLINE int DO_## type ## _NEG_OVERFLOW(type a, type * res) { \
if (a == MIN_ ## type) return 1; \
*res = -a; \
return 0; \
} \
static INLINE int type ## _NEG_OVERFLOW(type a) { \
return a == MIN_ ## type; \
} \
static INLINE int type ## _DIV_OVERFLOW(type a, type b) { \
return a == MIN_ ## type && b == -1; \
} \
static INLINE int DO_ ## type ## _DIV_OVERFLOW(type a, type b, type * res) { \
if (a == MIN_ ## type && b == -1) return 1; \
*res = a/b; \
return 0; \
} \
static INLINE int U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b) { \
unsigned type res; \
return DO_U ## type ## _MUL_OVERFLOW(a, b, &res); \
} \
static INLINE int U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b) { \
unsigned type res; \
return DO_U ## type ## _ADD_OVERFLOW(a, b, &res); \
} \
static INLINE int U ## type ## _SUB_OVERFLOW(unsigned type a, unsigned type b) { \
unsigned type res; \
return DO_U ## type ## _SUB_OVERFLOW(a, b, &res); \
} \
static INLINE int type ## _MUL_OVERFLOW(type a, type b) { \
type res; \
return DO_ ## type ## _MUL_OVERFLOW(a, b, &res); \
} \
static INLINE int type ## _ADD_OVERFLOW(type a, type b) { \
type res; \
return DO_ ## type ## _ADD_OVERFLOW(a, b, &res); \
} \
static INLINE int type ## _SUB_OVERFLOW(type a, type b) { \
type res; \
return DO_ ## type ## _SUB_OVERFLOW(a, b, &res); \
} \
static INLINE int type ## _MOD_OVERFLOW(type a, type b) { \
return type ## _DIV_OVERFLOW(a, b); \
} \
static INLINE int DO_ ## type ## _MOD_OVERFLOW(type a, type b, type * res) { \
if (type ## _MOD_OVERFLOW(a, b)) { \
return 1; \
} \
*res = a % b; \
return 0; \
} \
static INLINE int type ## _LSH_OVERFLOW(type a, type b) { \
type size = (type)sizeof(type)*CHAR_BIT; \
return (b < 0 || b >= size - 1 || a < 0 || (b && (a >> (size - 1 - b)))); \
} \
static INLINE int type ## _RSH_OVERFLOW(type a, type b) { \
return (b < 0 || a < 0 || b >= (type)sizeof(type)*CHAR_BIT); \
} \
static INLINE int DO_ ## type ## _LSH_OVERFLOW(type a, type b, type * res) { \
if (type ## _LSH_OVERFLOW(a, b)) return 1; \
*res = a << b; \
return 0; \
} \
static INLINE int DO_ ## type ## _RSH_OVERFLOW(type a, type b, type * res) { \
if (type ## _RSH_OVERFLOW(a, b)) return 1; \
*res = a >> b; \
return 0; \
}
#if PIKE_CLANG_BUILTIN(__builtin_uadd_overflow)
#define DO_CLANG_OF(name, type, builtin) \
static INLINE int name(type a, type b, type * res) { \
type tmp; \
if (builtin(a, b, &tmp)) return 1; \
*res = tmp; \
return 0; \
}
DO_CLANG_OF(DO_INT32_ADD_OVERFLOW, INT32, __builtin_sadd_overflow)
DO_CLANG_OF(DO_INT32_SUB_OVERFLOW, INT32, __builtin_ssub_overflow)
DO_CLANG_OF(DO_INT32_MUL_OVERFLOW, INT32, __builtin_smul_overflow)
DO_CLANG_OF(DO_UINT32_ADD_OVERFLOW, unsigned INT32, __builtin_uadd_overflow)
DO_CLANG_OF(DO_UINT32_SUB_OVERFLOW, unsigned INT32, __builtin_usub_overflow)
DO_CLANG_OF(DO_UINT32_MUL_OVERFLOW, unsigned INT32, __builtin_umul_overflow)
GENERIC_OVERFLOW_CHECKS(INT32)
#if defined(INT64)
# if SIZEOF_LONG == 8
DO_CLANG_OF(DO_INT64_ADD_OVERFLOW, INT64, __builtin_saddl_overflow)
DO_CLANG_OF(DO_INT64_SUB_OVERFLOW, INT64, __builtin_ssubl_overflow)
DO_CLANG_OF(DO_INT64_MUL_OVERFLOW, INT64, __builtin_smull_overflow)
DO_CLANG_OF(DO_UINT64_ADD_OVERFLOW, unsigned INT64, __builtin_uaddl_overflow)
DO_CLANG_OF(DO_UINT64_SUB_OVERFLOW, unsigned INT64, __builtin_usubl_overflow)
DO_CLANG_OF(DO_UINT64_MUL_OVERFLOW, unsigned INT64, __builtin_umull_overflow)
# elif SIZEOF_LONG_LONG == 8
DO_CLANG_OF(DO_INT64_ADD_OVERFLOW, INT64, __builtin_saddll_overflow)
DO_CLANG_OF(DO_INT64_SUB_OVERFLOW, INT64, __builtin_ssubll_overflow)
DO_CLANG_OF(DO_INT64_MUL_OVERFLOW, INT64, __builtin_smulll_overflow)
DO_CLANG_OF(DO_UINT64_ADD_OVERFLOW, unsigned INT64, __builtin_uaddll_overflow)
DO_CLANG_OF(DO_UINT64_SUB_OVERFLOW, unsigned INT64, __builtin_usubll_overflow)
DO_CLANG_OF(DO_UINT64_MUL_OVERFLOW, unsigned INT64, __builtin_umulll_overflow)
#endif
GENERIC_OVERFLOW_CHECKS(INT64)
#endif
#else
#define _GEN_OF2(type, type2, utype2, size) \
static INLINE int DO_ ## type ## _ADD_OVERFLOW(type a, type b, type * res) { \
type2 tmp; \
tmp = (type2)a + (type2)b; \
if (tmp < MIN_ ## type || tmp > MAX_ ## type) \
return 1; \
*res = (type)tmp; \
return 0; \
} \
static INLINE int DO_ ## type ## _SUB_OVERFLOW(type a, type b, type * res) { \
type2 tmp; \
tmp = (type2)a - (type2)b; \
if (tmp < MIN_ ## type || tmp > MAX_ ## type) \
return 1; \
*res = (type)tmp; \
return 0; \
} \
static INLINE int DO_ ## type ## _MUL_OVERFLOW(type a, type b, type * res) { \
type2 tmp; \
tmp = (type2)a * (type2)b; \
if (tmp < MIN_ ## type || tmp > MAX_ ## type) \
return 1; \
*res = (type)tmp; \
return 0; \
} \
static INLINE int DO_U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b, \
unsigned type * res) { \
utype2 tmp; \
tmp = (utype2)a + (utype2)b; \
if (tmp >> size) return 1; \
*res = (unsigned type)tmp; \
return 0; \
} \
static INLINE int DO_U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b, \
unsigned type * res) { \
utype2 tmp; \
tmp = (utype2)a * (utype2)b; \
if (tmp >> size) return 1; \
*res = (unsigned type)tmp; \
return 0; \
}
#define _GEN_OF1(type, size) \
static INLINE int DO_ ## type ## _ADD_OVERFLOW(type a, type b, type * res) { \
if ((b > 0 && a > MAX_ ## type - b) || \
(b < 0 && a < MIN_ ## type - b)) \
return 1; \
*res = a + b; \
return 0; \
} \
static INLINE int DO_ ## type ## _SUB_OVERFLOW(type a, type b, type * res) { \
if ((b > 0 && a < MIN_ ## type + b) || \
(b < 0 && a > MAX_ ## type + b)) \
return 1; \
*res = a - b; \
return 0; \
} \
static INLINE int DO_## type ## _MUL_OVERFLOW(type a, type b, type * res) { \
if (a > 0) { \
if (b > 0) { \
if (a > (MAX_ ## type / b)) { \
return 1; \
} \
} else { \
if (b < (MIN_ ## type / a)) { \
return 1; \
} \
} \
} else { \
if (b > 0) { \
if (a < (MAX_ ## type / b)) { \
return 1; \
} \
} else { \
if ( (a != 0) && (b < (MAX_ ## type / a))) { \
return 1; \
} \
} \
} \
*res = a * b; \
return 0; \
} \
static INLINE int DO_U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b, \
unsigned type * res) { \
if (a > MAX_U ## type - b) \
return 1; \
*res = a + b; \
return 0; \
} \
static INLINE int DO_U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b, \
unsigned type * res) { \
unsigned type tmp = 0; \
unsigned type bits = size/2; \
unsigned type low_mask = ((1 << bits)-1); \
unsigned type a1 = a >> bits; \
unsigned type b1 = b >> bits; \
unsigned type a0 = a & low_mask; \
unsigned type b0 = b & low_mask; \
tmp = a1 * b1; \
a1 *= b0; \
b1 *= a0; \
if (tmp || (a1|b1) & ~low_mask) return 1; \
tmp = a1<<bits; \
if (DO_U ## type ## _ADD_OVERFLOW(tmp, b1<<bits, &tmp) \
|| DO_U ## type ## _ADD_OVERFLOW(tmp, a0*b0, &tmp)) return 1; \
*res = tmp; \
return 0; \
} \
#define GEN_USUB_OF(type) \
static INLINE int DO_U ## type ## _SUB_OVERFLOW(unsigned type a, unsigned type b, \
unsigned type * res) { \
if (b > a) \
return 1; \
*res = a - b; \
return 0; \
} \
#define GEN_OF1(size) \
GEN_USUB_OF(INT ## size) \
_GEN_OF1(INT ## size, size) \
GENERIC_OVERFLOW_CHECKS(INT ## size)
#define GEN_OF2(s1, s2) \
GEN_USUB_OF(INT ## s1) \
_GEN_OF2(INT ## s1, INT ## s2, UINT ## s2, s1) \
GENERIC_OVERFLOW_CHECKS(INT ## s1)
#if defined(INT128) && defined(UINT128)
GEN_OF2(64, 128)
GEN_OF2(32, 64)
#elif defined(INT64) && defined(UINT64)
GEN_OF1(64)
GEN_OF2(32, 64)
#else
GEN_OF1(32)
#endif
#endif
#ifdef AUTO_BIGNUM
/* NB: GCC 4.1.2 doesn't alias pointers to INT_TYPE and to INT32/INT64,
* so the DO_INT_TYPE_*_OVERFLOW variants can't just be cpp-renames
* to the corresponding INT32/INT64 variant, as the stores to the
* target variable may get lost. We fix this by having variables
* of the correct type as temporaries, and then copying the result.
*/
#define _GEN_INT_TYPE_UNOP(OP, size) \
static INLINE int INT_TYPE_ ## OP ## _OVERFLOW(INT_TYPE a) { \
INT ## size tmp; \
return (DO_INT ## size ## _ ## OP ## _OVERFLOW(a, &tmp)); \
} \
static INLINE int DO_INT_TYPE_ ## OP ## _OVERFLOW(INT_TYPE a, \
INT_TYPE *res) { \
INT ## size tmp; \
if (DO_INT ## size ## _ ## OP ## _OVERFLOW(a, &tmp)) return 1; \
*res = tmp; \
return 0; \
}
#define _GEN_INT_TYPE_BINOP(OP, size) \
static INLINE int INT_TYPE_ ## OP ## _OVERFLOW(INT_TYPE a, \
INT_TYPE b) { \
INT ## size tmp; \
return (DO_INT ## size ## _ ## OP ## _OVERFLOW(a, b, &tmp)); \
} \
static INLINE int DO_INT_TYPE_ ## OP ## _OVERFLOW(INT_TYPE a, \
INT_TYPE b, \
INT_TYPE *res) { \
INT ## size tmp; \
if (DO_INT ## size ## _ ## OP ## _OVERFLOW(a, b, &tmp)) return 1; \
*res = tmp; \
return 0; \
}
#define GEN_INT_TYPE(size) \
_GEN_INT_TYPE_UNOP(NEG, size) \
_GEN_INT_TYPE_BINOP(MUL, size) \
_GEN_INT_TYPE_BINOP(ADD, size) \
_GEN_INT_TYPE_BINOP(SUB, size) \
_GEN_INT_TYPE_BINOP(DIV, size) \
_GEN_INT_TYPE_BINOP(MOD, size) \
_GEN_INT_TYPE_BINOP(LSH, size) \
_GEN_INT_TYPE_BINOP(RSH, size)
#if SIZEOF_INT_TYPE == 8
GEN_INT_TYPE(64)
#elif SIZEOF_INT_TYPE == 4
GEN_INT_TYPE(32)
#endif
/* Prototypes begin here */
PMOD_EXPORT extern struct svalue auto_bignum_program;
PMOD_EXPORT struct program *get_auto_bignum_program(void);
PMOD_EXPORT struct program *get_auto_bignum_program_or_zero(void);
void init_auto_bignum(void);
void exit_auto_bignum(void);
PMOD_EXPORT void convert_stack_top_to_bignum(void);
PMOD_EXPORT void convert_stack_top_with_base_to_bignum(void);
int is_bignum_object(struct object *o);
PMOD_EXPORT int is_bignum_object_in_svalue(struct svalue *sv);
PMOD_EXPORT struct object *make_bignum_object(void);
PMOD_EXPORT struct object *bignum_from_svalue(struct svalue *s);
PMOD_EXPORT struct pike_string *string_from_bignum(struct object *o, int base);
PMOD_EXPORT void convert_svalue_to_bignum(struct svalue *s);
#ifdef INT64
PMOD_EXPORT extern void (*push_int64)(INT64 i);
/* Returns nonzero iff conversion is successful. */
PMOD_EXPORT extern int (*int64_from_bignum) (INT64 *i, struct object *bignum);
PMOD_EXPORT extern void (*reduce_stack_top_bignum) (void);
#else
#define push_int64(i) push_int((INT_TYPE)(i))
#define int64_from_bignum(I,BIGNUM) 0
#endif /* INT64 */
PMOD_EXPORT extern void (*push_ulongest) (unsigned LONGEST i);
PMOD_EXPORT extern int (*ulongest_from_bignum) (unsigned LONGEST *i,
struct object *bignum);
PMOD_EXPORT void hook_in_gmp_funcs (
#ifdef INT64
void (*push_int64_val)(INT64),
int (*int64_from_bignum_val) (INT64 *, struct object *),
void (*reduce_stack_top_bignum_val) (void),
#endif
void (*push_ulongest_val) (unsigned LONGEST),
int (*ulongest_from_bignum_val) (unsigned LONGEST *, struct object *));
/* Prototypes end here */
#else
#define push_int64(i) push_int((INT_TYPE)(i))
#define push_ulongest(i) push_int((INT_TYPE)(i))
#define int64_from_bignum(I,BIGNUM) 0
#define ulongest_from_bignum(I,BIGNUM) 0
#endif /* AUTO_BIGNUM */
/* Less confusing name, considering that push_int64 pushes a 32 bit
* int if INT64 isn't available. */
#define push_longest push_int64
#endif /* BIGNUM_H */
|