Redesigned RTypesOverflow apis to capture the result and don't duplicate ops ##util

This commit is contained in:
pancake 2026-02-13 13:45:24 +01:00 committed by GitHub
parent dad9f2b826
commit 0ad445e5ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 754 additions and 303 deletions

View file

@ -487,12 +487,12 @@ and then check for null.
For example:
```c
if (ST32_ADD_OVFCHK (sizeof (Object), counter)) {
void *amount = calloc (sizeof (Object), counter);
if (!amount) {
R_LOG_DEBUG ("Cannot allocate %d objects", counter);
return;
}
st32 alloc_size;
if (r_mul_overflow_st32 (sizeof (Object), counter, &alloc_size)) {
R_LOG_DEBUG ("Overflow when computing allocation size");
return;
}
void *amount = calloc (sizeof (Object), counter);
```
### Stack allocations

View file

@ -57,8 +57,13 @@ static int read_ahead(ReadAhead *ra, RAnal *anal, ut64 addr, ut8 *buf, int len)
bool is_cached = false;
#if READ_AHEAD
if (ra->cache_addr != UT64_MAX && addr >= ra->cache_addr && addr < ra->cache_addr + sizeof (ra->cache)) {
ut64 addr_end = UT64_ADD_OVFCHK (addr, len)? UT64_MAX: addr + len;
ut64 cache_addr_end = UT64_ADD_OVFCHK (ra->cache_addr, cache_len)? UT64_MAX: ra->cache_addr + cache_len;
ut64 addr_end, cache_addr_end;
if (r_add_overflow (addr, (ut64)len, &addr_end)) {
addr_end = UT64_MAX;
}
if (r_add_overflow (ra->cache_addr, (ut64)cache_len, &cache_addr_end)) {
cache_addr_end = UT64_MAX;
}
is_cached = ((addr != UT64_MAX) && (addr >= ra->cache_addr) && (addr_end < cache_addr_end));
}
#endif
@ -2681,10 +2686,10 @@ static void update_var_analysis(RAnalFunction *fcn, int align, ut64 from, ut64 t
int opsz;
from = align ? from - (from % align) : from;
to = align ? R_ROUND (to, align) : to;
if (UT64_SUB_OVFCHK (to, from)) {
ut64 len;
if (r_sub_overflow (to, from, &len)) {
return;
}
ut64 len = to - from;
ut8 *buf = malloc (len);
if (!buf) {
return;

View file

@ -157,7 +157,8 @@ static int drcov_parse(RAnal *anal, const char *path, DrcovBbCb cb, void *user)
return -1;
}
if (SZT_MUL_OVFCHK (module_count, sizeof (DrcovModule))) {
size_t alloc_size;
if (r_mul_overflow_size_t (module_count, sizeof (DrcovModule), &alloc_size)) {
R_LOG_ERROR ("Module table too large in '%s'", path);
free (buf);
return -1;
@ -229,17 +230,18 @@ static int drcov_parse(RAnal *anal, const char *path, DrcovBbCb cb, void *user)
continue;
}
DrcovModule *mod = &modules[mod_id];
if (UT64_ADD_OVFCHK (mod->base, start)) {
ut64 addr;
if (r_add_overflow (mod->base, (ut64)start, &addr)) {
continue;
}
ut64 addr = mod->base + start;
if (size && UT64_ADD_OVFCHK (addr, size)) {
ut64 addr_end;
if (size && r_add_overflow (addr, (ut64)size, &addr_end)) {
continue;
}
if (mod->end && mod->end != UT64_MAX && addr > mod->end) {
continue;
}
if (size && mod->end && mod->end != UT64_MAX && addr + size > mod->end) {
if (size && mod->end && mod->end != UT64_MAX && addr_end > mod->end) {
continue;
}
if (cb && cb (user, addr, size)) {

View file

@ -17,18 +17,20 @@ R_API ut64 r_anal_value_to_ut64(RAnal *anal, RAnalValue *val) {
ut64 num = val->base + (val->delta * (val->mul ? val->mul : 1));
if (val->reg) {
st64 n = (st64)r_reg_getv (anal->reg, val->reg);
if (ST64_ADD_OVFCHK (num, n)) {
st64 result;
if (r_add_overflow ((st64)num, n, &result)) {
num = UT64_MAX;
} else {
num += n;
num = result;
}
}
if (val->regdelta) {
st64 n = (st64)r_reg_getv (anal->reg, val->regdelta);
if (ST64_ADD_OVFCHK (num, n)) {
st64 result;
if (r_add_overflow ((st64)num, n, &result)) {
num = UT64_MAX;
} else {
num += n;
num = result;
}
}
switch (val->memref) {

View file

@ -153,10 +153,10 @@ static bool dalvik_read_payload(RBuffer *buf, const struct dalvik_instr *instr,
}
st32 first_key = r_read_le32 (&v[2]);
if (SZT_MUL_OVFCHK (len, sizeof (st32))) {
size_t targets_size;
if (r_mul_overflow ((size_t)len, sizeof (st32), &targets_size)) {
return false;
}
size_t targets_size = (size_t)len * sizeof (st32);
st32 *targets = malloc (targets_size);
if (targets == NULL) {
return false;
@ -185,10 +185,10 @@ static bool dalvik_read_payload(RBuffer *buf, const struct dalvik_instr *instr,
return false;
}
if (SZT_MUL_OVFCHK (len, sizeof (st32))) {
size_t size;
if (r_mul_overflow ((size_t)len, sizeof (st32), &size)) {
return false;
}
size_t size = (size_t)len * sizeof (st32);
st32 *keys = malloc (size);
st32 *targets = malloc (size);
if (keys == NULL || targets == NULL) {
@ -229,10 +229,10 @@ static bool dalvik_read_payload(RBuffer *buf, const struct dalvik_instr *instr,
return false;
}
if (SZT_MUL_OVFCHK (len, element_width)) {
size_t size;
if (r_mul_overflow ((size_t)len, (size_t)element_width, &size)) {
return false;
}
size_t size = (size_t)len * (size_t)element_width;
R_RETURN_VAL_IF_FAIL (size < 0x10000000, false);
ut8 *data = malloc (size);
if (data == NULL) {

View file

@ -1,44 +1,44 @@
/* radare2 - LGPL - Copyright 2018 - thestr4ng3r */
/* radare2 - LGPL - Copyright 2018-2026 - thestr4ng3r */
#include "pic_baseline.h"
static const PicBaselineOpInfo pic_baseline_op_info[PIC_BASELINE_OPCODE_INVALID] = {
{ "nop", PIC_BASELINE_OP_ARGS_NONE },
{ "option", PIC_BASELINE_OP_ARGS_NONE },
{ "sleep", PIC_BASELINE_OP_ARGS_NONE },
{ "clrwdt", PIC_BASELINE_OP_ARGS_NONE },
{ "tris", PIC_BASELINE_OP_ARGS_3F },
{ "movlb", PIC_BASELINE_OP_ARGS_3K },
{ "return", PIC_BASELINE_OP_ARGS_NONE },
{ "retfie", PIC_BASELINE_OP_ARGS_NONE },
{ "movwf", PIC_BASELINE_OP_ARGS_5F },
{ "clrf", PIC_BASELINE_OP_ARGS_5F },
{ "clrw", PIC_BASELINE_OP_ARGS_NONE },
{ "subwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "decf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "iorwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "andwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "xorwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "andwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "movf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "comf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "incf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "decfsz", PIC_BASELINE_OP_ARGS_1D_5F },
{ "rrf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "rlf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "swapf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "incfsz", PIC_BASELINE_OP_ARGS_1D_5F },
{ "bcf", PIC_BASELINE_OP_ARGS_3B_5F },
{ "bsf", PIC_BASELINE_OP_ARGS_3B_5F },
{ "btfsc", PIC_BASELINE_OP_ARGS_3B_5F },
{ "btfss", PIC_BASELINE_OP_ARGS_3B_5F },
{ "retlw", PIC_BASELINE_OP_ARGS_8K },
{ "call", PIC_BASELINE_OP_ARGS_8K },
{ "goto", PIC_BASELINE_OP_ARGS_9K },
{ "movlw", PIC_BASELINE_OP_ARGS_8K },
{ "iorlw", PIC_BASELINE_OP_ARGS_8K },
{ "andlw", PIC_BASELINE_OP_ARGS_8K },
{ "xorlw", PIC_BASELINE_OP_ARGS_8K }
{ "nop", PIC_BASELINE_OP_ARGS_NONE },
{ "option", PIC_BASELINE_OP_ARGS_NONE },
{ "sleep", PIC_BASELINE_OP_ARGS_NONE },
{ "clrwdt", PIC_BASELINE_OP_ARGS_NONE },
{ "tris", PIC_BASELINE_OP_ARGS_3F },
{ "movlb", PIC_BASELINE_OP_ARGS_3K },
{ "return", PIC_BASELINE_OP_ARGS_NONE },
{ "retfie", PIC_BASELINE_OP_ARGS_NONE },
{ "movwf", PIC_BASELINE_OP_ARGS_5F },
{ "clrf", PIC_BASELINE_OP_ARGS_5F },
{ "clrw", PIC_BASELINE_OP_ARGS_NONE },
{ "subwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "decf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "iorwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "andwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "xorwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "andwf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "movf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "comf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "incf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "decfsz", PIC_BASELINE_OP_ARGS_1D_5F },
{ "rrf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "rlf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "swapf", PIC_BASELINE_OP_ARGS_1D_5F },
{ "incfsz", PIC_BASELINE_OP_ARGS_1D_5F },
{ "bcf", PIC_BASELINE_OP_ARGS_3B_5F },
{ "bsf", PIC_BASELINE_OP_ARGS_3B_5F },
{ "btfsc", PIC_BASELINE_OP_ARGS_3B_5F },
{ "btfss", PIC_BASELINE_OP_ARGS_3B_5F },
{ "retlw", PIC_BASELINE_OP_ARGS_8K },
{ "call", PIC_BASELINE_OP_ARGS_8K },
{ "goto", PIC_BASELINE_OP_ARGS_9K },
{ "movlw", PIC_BASELINE_OP_ARGS_8K },
{ "iorlw", PIC_BASELINE_OP_ARGS_8K },
{ "andlw", PIC_BASELINE_OP_ARGS_8K },
{ "xorlw", PIC_BASELINE_OP_ARGS_8K }
};
PicBaselineOpcode pic_baseline_get_opcode(ut16 instr) {
@ -52,7 +52,7 @@ PicBaselineOpcode pic_baseline_get_opcode(ut16 instr) {
case 0x5: // 0b000101
return PIC_BASELINE_OPCODE_ANDWF;
case 0x1: // 0b000001
if (instr & (1 << 5)) {
if (instr &(1 << 5)) {
return PIC_BASELINE_OPCODE_CLRF;
}
if ((instr & 0x1f) == 0) { // last 5 bits
@ -74,7 +74,7 @@ PicBaselineOpcode pic_baseline_get_opcode(ut16 instr) {
case 0x8: // 0b001000
return PIC_BASELINE_OPCODE_MOVF;
case 0x0:
if (instr & (1 << 5)) {
if (instr &(1 << 5)) {
return PIC_BASELINE_OPCODE_MOVWF;
} else {
switch (instr & 0x1f) { // last 5 bits
@ -190,10 +190,11 @@ const PicBaselineOpInfo *pic_baseline_get_op_info(PicBaselineOpcode opcode) {
}
char *pic_baseline_disassemble(const ut8 *b, int l, int *opsz) {
#define EMIT_INVALID { \
*opsz = 1; \
return NULL; \
}
#define EMIT_INVALID \
{ \
*opsz = 1; \
return NULL; \
}
if (!b || l < 2) {
return NULL;
}
@ -208,13 +209,13 @@ char *pic_baseline_disassemble(const ut8 *b, int l, int *opsz) {
*opsz = 2;
const PicBaselineOpInfo *op_info = pic_baseline_get_op_info(opcode);
const PicBaselineOpInfo *op_info = pic_baseline_get_op_info (opcode);
if (!op_info) {
return NULL;
}
r_strf_buffer (64);
const char *buf_asm;
const char *buf_asm = "unknown";
switch (op_info->args) {
case PIC_BASELINE_OP_ARGS_NONE:
buf_asm = op_info->mnemonic;
@ -229,15 +230,13 @@ char *pic_baseline_disassemble(const ut8 *b, int l, int *opsz) {
buf_asm = r_strf ("%s 0x%x", op_info->mnemonic, instr & PIC_BASELINE_OP_ARGS_3K_MASK_K);
break;
case PIC_BASELINE_OP_ARGS_1D_5F:
buf_asm = r_strf ("%s 0x%x, %c", op_info->mnemonic, instr & PIC_BASELINE_OP_ARGS_1D_5F_MASK_F,
(instr & PIC_BASELINE_OP_ARGS_1D_5F_MASK_D) >> 5 ? 'f' : 'w');
buf_asm = r_strf ("%s 0x%x, %c", op_info->mnemonic, instr & PIC_BASELINE_OP_ARGS_1D_5F_MASK_F, (instr & PIC_BASELINE_OP_ARGS_1D_5F_MASK_D) >> 5? 'f': 'w');
break;
case PIC_BASELINE_OP_ARGS_5F:
buf_asm = r_strf ("%s 0x%x", op_info->mnemonic, instr & PIC_BASELINE_OP_ARGS_5F_MASK_F);
break;
case PIC_BASELINE_OP_ARGS_3B_5F:
buf_asm = r_strf ("%s 0x%x, 0x%x", op_info->mnemonic, instr & PIC_BASELINE_OP_ARGS_3B_5F_MASK_F,
(instr & PIC_BASELINE_OP_ARGS_3B_5F_MASK_B) >> 5);
buf_asm = r_strf ("%s 0x%x, 0x%x", op_info->mnemonic, instr & PIC_BASELINE_OP_ARGS_3B_5F_MASK_F, (instr & PIC_BASELINE_OP_ARGS_3B_5F_MASK_B) >> 5);
break;
case PIC_BASELINE_OP_ARGS_8K:
buf_asm = r_strf ("%s 0x%x", op_info->mnemonic, instr & PIC_BASELINE_OP_ARGS_8K_MASK_K);

View file

@ -389,7 +389,8 @@ static bool r_bin_xcoff_init_opt_hdr(RBinCoffObj *obj) {
#endif
static bool r_bin_coff_init_scn_hdr(RBinCoffObj *obj) {
int ret, size;
int ret;
size_t size;
ut32 f_nscns;
ut64 offset = 0;
@ -403,8 +404,7 @@ static bool r_bin_coff_init_scn_hdr(RBinCoffObj *obj) {
f_nscns = obj->hdr.f_nscns;
f_magic = obj->hdr.f_magic;
}
if (ST32_MUL_OVFCHK (sizeof (struct coff_scn_hdr), f_nscns)) {
// if ((st32)f_nscns < 1 || f_nscns > UT16_MAX)
if (r_mul_overflow ((size_t)sizeof (struct coff_scn_hdr), (size_t)f_nscns, &size)) {
R_LOG_WARN ("Dimming f_nscns count because is poluted or too large");
f_nscns &= 0xff;
if (obj->type == COFF_TYPE_BIGOBJ) {
@ -412,13 +412,13 @@ static bool r_bin_coff_init_scn_hdr(RBinCoffObj *obj) {
} else {
obj->hdr.f_nscns = f_nscns;
}
size = f_nscns * sizeof (struct coff_scn_hdr);
}
if (f_magic == COFF_FILE_TI_COFF) {
offset += 2;
}
size = f_nscns * sizeof (struct coff_scn_hdr);
if (offset > obj->size || offset + size > obj->size || size < 0) {
if (offset > obj->size || offset + size > obj->size) {
return false;
}
obj->scn_hdrs = calloc (1, size + sizeof (struct coff_scn_hdr));
@ -510,7 +510,8 @@ static bool r_bin_coff_init_symtable(RBinCoffObj *obj) {
if (!f_nsyms) {
return true;
}
if (ST32_MUL_OVFCHK (symbol_size, f_nsyms)) {
size_t size;
if (r_mul_overflow ((size_t)symbol_size, (size_t)f_nsyms, &size)) {
R_LOG_WARN ("Dimming f_nsyms count because is poluted or too large");
f_nsyms = 1;
if (obj->type == COFF_TYPE_BIGOBJ) {
@ -518,9 +519,9 @@ static bool r_bin_coff_init_symtable(RBinCoffObj *obj) {
} else {
obj->hdr.f_nsyms = f_nsyms;
}
size = f_nsyms * symbol_size;
}
int size = f_nsyms * symbol_size;
if (size < 0 || size > obj->size || offset > obj->size || offset + size > obj->size) {
if (size > obj->size || offset > obj->size || offset + size > obj->size) {
R_FREE (obj->bigobj_symbols);
R_FREE (obj->symbols);
return false;
@ -560,7 +561,8 @@ static bool r_bin_coff_init_scn_va(RBinCoffObj *obj) {
R_LOG_WARN ("Invalid amount of f_nscns %d", f_nscns);
return true;
}
if (ST32_MUL_OVFCHK (sizeof (struct coff_scn_hdr), f_nscns)) {
st32 alloc_size;
if (r_mul_overflow_st32 (sizeof (struct coff_scn_hdr), f_nscns, &alloc_size)) {
R_LOG_WARN ("Dimming f_nscns count because is poluted or too large");
f_nscns &= 0xff;
return false;

View file

@ -193,15 +193,16 @@ RCoreSymCacheElement *r_coresym_cache_element_new(RBinFile *bf, RBuffer *buf, ut
ut64 page_zero_size = 0;
size_t page_zero_idx = 0;
if (UT32_MUL_OVFCHK (hdr->n_segments, sizeof (RCoreSymCacheElementSegment))) {
ut32 tmp;
if (r_mul_overflow_ut32 (hdr->n_segments, sizeof (RCoreSymCacheElementSegment), &tmp)) {
goto beach;
} else if (UT32_MUL_OVFCHK (hdr->n_sections, sizeof (RCoreSymCacheElementSection))) {
} else if (r_mul_overflow_ut32 (hdr->n_sections, sizeof (RCoreSymCacheElementSection), &tmp)) {
goto beach;
} else if (UT32_MUL_OVFCHK (hdr->n_symbols, sizeof (RCoreSymCacheElementSymbol))) {
} else if (r_mul_overflow_ut32 (hdr->n_symbols, sizeof (RCoreSymCacheElementSymbol), &tmp)) {
goto beach;
} else if (UT32_MUL_OVFCHK (hdr->n_lined_symbols, sizeof (RCoreSymCacheElementLinedSymbol))) {
} else if (r_mul_overflow_ut32 (hdr->n_lined_symbols, sizeof (RCoreSymCacheElementLinedSymbol), &tmp)) {
goto beach;
} else if (UT32_MUL_OVFCHK (hdr->n_line_info, sizeof (RCoreSymCacheElementLineInfo))) {
} else if (r_mul_overflow_ut32 (hdr->n_line_info, sizeof (RCoreSymCacheElementLineInfo), &tmp)) {
goto beach;
}
if (hdr->n_segments > 0) {

View file

@ -3002,13 +3002,10 @@ static void parse_symbols(RBinFile *bf, struct MACH0_(obj_t) *mo, HtPP *symcache
return;
}
if (SZT_MUL_OVFCHK (symbols_count, 2 * sizeof (RBinSymbol))) {
// overflow may happen here
if (r_mul_overflow (symbols_count, 2 * sizeof (RBinSymbol), &symbols_size)) {
ht_pp_free (hash);
return;
}
symbols_size = symbols_count * 2 * sizeof (RBinSymbol);
j = 0; // symbol_idx
mo->main_addr = UT64_MAX;
int bits = MACH0_(get_bits_from_hdr) (&mo->hdr);

View file

@ -183,13 +183,13 @@ static int init_pdb7_root_stream(RBinPdb *pdb, int *root_page_list, int pages_am
R_FREE (sizes);
return 0;
}
if (SZT_MUL_OVFCHK (num_pages, 4)) {
ut32 size;
if (r_mul_overflow (num_pages, (ut32)4, &size)) {
R_LOG_WARN ("num_pages overflow");
R_FREE (data);
R_FREE (sizes);
return 0;
}
ut32 size = num_pages * 4;
if (size > UT16_MAX) {
R_LOG_WARN ("too many pages");
R_FREE (data);
@ -480,10 +480,11 @@ static bool pdb7_parse(RBinPdb *pdb) {
}
p_tmp = root_page_data;
for (i = 0; i < num_root_index_pages; i++) {
if (UT64_MUL_OVFCHK (root_index_pages[i], page_size)) {
ut64 seek_pos;
if (r_mul_overflow ((ut64)root_index_pages[i], (ut64)page_size, &seek_pos)) {
break;
}
r_buf_seek (pdb->buf, root_index_pages[i] * page_size, R_BUF_SET);
r_buf_seek (pdb->buf, seek_pos, R_BUF_SET);
r_buf_read (pdb->buf, p_tmp, page_size);
p_tmp = (char *)p_tmp + page_size;
}

View file

@ -4396,10 +4396,10 @@ static struct r_bin_pe_section_t *PE_(r_bin_pe_get_sections)(RBinPEObj *pe) {
ut64 sym_tbl_off = pe->nt_headers->file_header.PointerToSymbolTable;
const int num_symbols = pe->nt_headers->file_header.NumberOfSymbols;
if (ST32_MUL_OVFCHK (num_symbols, COFF_SYMBOL_SIZE)) {
st64 off;
if (r_mul_overflow ((st64)num_symbols, (st64)COFF_SYMBOL_SIZE, &off)) {
continue;
}
st64 off = num_symbols * COFF_SYMBOL_SIZE;
if (off > 0 && sym_tbl_off &&
sym_tbl_off + off + idx < pe->size &&
sym_tbl_off + off + idx > off) {

View file

@ -426,7 +426,7 @@ static RBinReloc *reloc_convert(ELFOBJ* eo, RBinElfReloc *rel, ut64 got_addr) {
ut64 sym_vaddr = r->symbol ? r->symbol->vaddr : (rel->sym ? rel->rva : 0);
#define SET(T) r->type = R_BIN_RELOC_ ## T; r->additive = 0; return r
#define ADD(T, A) r->type = R_BIN_RELOC_ ## T; if (!ST32_ADD_OVFCHK (r->addend, A)) { r->addend += A; } r->additive = rel->mode == DT_RELA || rel->mode == DT_CREL; return r
#define ADD(T, A) do { r->type = R_BIN_RELOC_ ## T; st32 _tmp; if (!r_add_overflow_st32 (r->addend, A, &_tmp)) { r->addend = _tmp; } r->additive = rel->mode == DT_RELA || rel->mode == DT_CREL; return r; } while (0)
// Early return if it's a CREL relocation - it was already set up in the initialization above
if (rel->mode == DT_CREL) {

View file

@ -41,18 +41,17 @@ static bool validate_header(RBinXtacObj *bin) {
hdr->size_of_nt_pname > 0xfff * sizeof (ut16)) {
return false;
}
if (UT64_ADD_OVFCHK (hdr->ptr_to_addr_pairs, (ut64)hdr->num_of_addr_pairs * sizeof (X86ArmAddrPair))) {
ut64 addr_pairs_end, mod_name_end, nt_pname_end;
if (r_add_overflow ((ut64)hdr->ptr_to_addr_pairs, (ut64)hdr->num_of_addr_pairs * sizeof (X86ArmAddrPair), &addr_pairs_end)) {
return false;
}
if (UT64_ADD_OVFCHK (hdr->ptr_to_mod_name, hdr->size_of_mod_name)) {
if (r_add_overflow ((ut64)hdr->ptr_to_mod_name, (ut64)hdr->size_of_mod_name, &mod_name_end)) {
return false;
}
if (UT64_ADD_OVFCHK (hdr->ptr_to_nt_pname, hdr->size_of_nt_pname)) {
if (r_add_overflow ((ut64)hdr->ptr_to_nt_pname, (ut64)hdr->size_of_nt_pname, &nt_pname_end)) {
return false;
}
if ((ut64)hdr->ptr_to_addr_pairs + (ut64)hdr->num_of_addr_pairs * sizeof (X86ArmAddrPair) > buf_size ||
(ut64)hdr->ptr_to_mod_name + hdr->size_of_mod_name > buf_size ||
(ut64)hdr->ptr_to_nt_pname + hdr->size_of_nt_pname > buf_size) {
if (addr_pairs_end > buf_size || mod_name_end > buf_size || nt_pname_end > buf_size) {
return false;
}
if (hdr->ptr_to_head_blck_stub > buf_size ||
@ -96,12 +95,11 @@ static RList *sections(RBinFile *bf) {
s->paddr = ptr_addr;
s->vaddr = ptr_addr;
s->perm = R_PERM_RX;
if (UT32_ADD_OVFCHK (ptr_addr, blck_stub_code_size)) {
if (r_add_overflow (ptr_addr, blck_stub_code_size, &ptr_addr)) {
free (s->name);
free (s);
continue;
}
ptr_addr += blck_stub_code_size;
r_list_append (ret, s);
if (blck_stub_header->offset_to_next_entry < blck_stub_code_size) {
@ -115,18 +113,16 @@ static RList *sections(RBinFile *bf) {
s->paddr = ptr_addr;
s->vaddr = ptr_addr;
s->perm = R_PERM_RX;
if (UT32_ADD_OVFCHK (ptr_addr, size_of_trans_code)) {
if (r_add_overflow (ptr_addr, size_of_trans_code, &ptr_addr)) {
free (s->name);
free (s);
continue;
}
ptr_addr += size_of_trans_code;
r_list_append (ret, s);
if (UT32_ADD_OVFCHK (ptr_addr, sizeof (RBinBlckStubHeader) - 4)) {
break; // Overflow detected, stop processing
if (r_add_overflow (ptr_addr, (ut32)(sizeof (RBinBlckStubHeader) - 4), &ptr_addr)) {
break;
}
ptr_addr += sizeof (RBinBlckStubHeader) - 4;
}
return ret;

View file

@ -4,7 +4,8 @@
#include <r_util/r_print.h>
R_API RConsPixel *r_cons_pixel_new(int w, int h) {
if (UT32_MUL_OVFCHK (w, h)) {
size_t buf_size;
if (r_mul_overflow ((size_t)w, (size_t)h, &buf_size)) {
return NULL;
}
RConsPixel *p = R_NEW (RConsPixel);
@ -13,7 +14,7 @@ R_API RConsPixel *r_cons_pixel_new(int w, int h) {
}
p->w = w;
p->h = h;
p->buf_size = ((size_t)w) * h;
p->buf_size = buf_size;
p->buf = calloc (w, h);
if (!p->buf) {
free (p);

View file

@ -3200,8 +3200,9 @@ static void add_section(RCore *core, RBinSection *sec, ut64 addr, int fd) {
return;
}
if (!r_io_desc_get (core->io, fd) || UT64_ADD_OVFCHK (sec->size, sec->paddr) ||
UT64_ADD_OVFCHK (sec->size, addr) || !sec->vsize) {
ut64 tmp;
if (!r_io_desc_get (core->io, fd) || r_add_overflow_ut64 (sec->size, sec->paddr, &tmp) ||
r_add_overflow_ut64 (sec->size, addr, &tmp) || !sec->vsize) {
return;
}

View file

@ -3256,10 +3256,11 @@ reaccept:
r_socket_read_block (c, &flg, 1); // flags
R_LOG_DEBUG ("open (%d)", cmd);
r_socket_read_block (c, &cmd, 1); // len
if (UT8_ADD_OVFCHK (cmd, 1)) {
ut8 alloc_size;
if (r_add_overflow (cmd, (ut8)1, &alloc_size)) {
goto out_of_function;
}
ptr = malloc ((size_t)cmd + 1);
ptr = malloc ((size_t)alloc_size);
pipefd = -1;
if (!ptr) {
R_LOG_ERROR ("Cannot malloc in rmt-open len = %d", cmd);
@ -3317,12 +3318,13 @@ reaccept:
}
r_core_block_read (core);
/* Prevent size overflow on allocation */
if (SZT_ADD_OVFCHK ((size_t)i, 5)) {
size_t alloc_size;
if (r_add_overflow ((size_t)i, (size_t)5, &alloc_size)) {
R_LOG_ERROR ("rap: size overflow for read length %d", i);
r_socket_close (c);
goto out_of_function;
}
ptr = malloc ((size_t)i + 5);
ptr = malloc (alloc_size);
if (!ptr) {
R_LOG_ERROR ("rap: cannot allocate %zu bytes for read", (size_t)i + 5);
r_socket_close (c);

View file

@ -1122,7 +1122,7 @@ static bool esil_signed_mod(REsil *esil) {
char *src = r_esil_pop (esil);
if (src && r_esil_get_parm (esil, src, (ut64 *)&s)) {
if (dst && r_esil_get_parm (esil, dst, (ut64 *)&d)) {
if (ST64_DIV_OVFCHK (d, s)) {
if (r_div_overflow_st64 (d, s)) {
R_LOG_DEBUG ("0x%08"PFMT64x" esil_mod: Division by zero!", esil->addr);
esil->trap = R_ANAL_TRAP_DIVBYZERO;
esil->trap_code = 0;
@ -1199,7 +1199,7 @@ static bool esil_signed_div(REsil *esil) {
char *src = r_esil_pop (esil);
if (src && r_esil_get_parm (esil, src, (ut64 *)&s)) {
if (dst && r_esil_get_parm (esil, dst, (ut64 *)&d)) {
if (ST64_DIV_OVFCHK (d, s)) {
if (r_div_overflow_st64 (d, s)) {
R_LOG_DEBUG ("esil_div: Division by zero!");
esil->trap = R_ANAL_TRAP_DIVBYZERO;
esil->trap_code = 0;

View file

@ -5,124 +5,170 @@
extern "C" {
#endif
#if defined(__GNUC__) || defined(__clang__)
#define R_HAVE_OVERFLOW_BUILTINS 1
#if defined(__has_builtin)
# if __has_builtin(__builtin_add_overflow) && \
__has_builtin(__builtin_sub_overflow) && \
__has_builtin(__builtin_mul_overflow)
# define R_HAVE_BUILTIN_OVERFLOW 1
# endif
#endif
#ifdef R_HAVE_OVERFLOW_BUILTINS
#if defined(__GNUC__) && !defined(R_HAVE_BUILTIN_OVERFLOW)
# define R_HAVE_BUILTIN_OVERFLOW 1
#endif
#define SZT_ADD_OVFCHK(x,y) ({ size_t _r; __builtin_add_overflow ((x), (y), &_r); })
#define SSZT_ADD_OVFCHK(a,x) ({ ssize_t _r; __builtin_add_overflow ((a), (x), &_r); })
#define UT64_ADD_OVFCHK(x,y) ({ ut64 _r; __builtin_add_overflow ((x), (y), &_r); })
#define ST64_ADD_OVFCHK(a,x) ({ st64 _r; __builtin_add_overflow ((a), (x), &_r); })
#define UT32_ADD_OVFCHK(x,y) ({ ut32 _r; __builtin_add_overflow ((x), (y), &_r); })
#define ST32_ADD_OVFCHK(a,x) ({ st32 _r; __builtin_add_overflow ((a), (x), &_r); })
#define UT16_ADD_OVFCHK(x,y) ({ ut16 _r; __builtin_add_overflow ((x), (y), &_r); })
#define ST16_ADD_OVFCHK(a,b) ({ st16 _r; __builtin_add_overflow ((a), (b), &_r); })
#define UT8_ADD_OVFCHK(x,y) ({ ut8 _r; __builtin_add_overflow ((x), (y), &_r); })
#define ST8_ADD_OVFCHK(a,x) ({ st8 _r; __builtin_add_overflow ((a), (x), &_r); })
#define R_DEFINE_UNSIGNED_OVERFLOW(T, TMAX) \
static inline bool r_add_overflow_##T(T a, T b, T *res) { \
*res = a + b; \
return *res < a; \
} \
static inline bool r_sub_overflow_##T(T a, T b, T *res) { \
*res = a - b; \
return a < b; \
} \
static inline bool r_mul_overflow_##T(T a, T b, T *res) { \
if (a == 0 || b == 0) { \
*res = 0; \
return false; \
} \
if (a > (TMAX) / b) { \
return true; \
} \
*res = a * b; \
return false; \
}
#define SZT_SUB_OVFCHK(a,b) ({ size_t _r; __builtin_sub_overflow ((a), (b), &_r); })
#define SSZT_SUB_OVFCHK(a,b) ({ ssize_t _r; __builtin_sub_overflow ((a), (b), &_r); })
#define UT64_SUB_OVFCHK(a,b) ({ ut64 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define ST64_SUB_OVFCHK(a,b) ({ st64 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define UT32_SUB_OVFCHK(a,b) ({ ut32 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define ST32_SUB_OVFCHK(a,b) ({ st32 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define UT16_SUB_OVFCHK(a,b) ({ ut16 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define ST16_SUB_OVFCHK(a,b) ({ st16 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define UT8_SUB_OVFCHK(a,b) ({ ut8 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define ST8_SUB_OVFCHK(a,b) ({ st8 _r; __builtin_sub_overflow ((a), (b), &_r); })
#define R_DEFINE_SIGNED_OVERFLOW(T, TMAX, TMIN) \
static inline bool r_add_overflow_##T(T a, T b, T *res) { \
if ((b > 0 && a > (TMAX) - b) || \
(b < 0 && a < (TMIN) - b)) { \
return true; \
} \
*res = a + b; \
return false; \
} \
static inline bool r_sub_overflow_##T(T a, T b, T *res) { \
if ((b < 0 && a > (TMAX) + b) || \
(b > 0 && a < (TMIN) + b)) { \
return true; \
} \
*res = a - b; \
return false; \
} \
static inline bool r_mul_overflow_##T(T a, T b, T *res) { \
if (a == 0 || b == 0) { \
*res = 0; \
return false; \
} \
if (a == -1 && b == (TMIN)) { return true; } \
if (b == -1 && a == (TMIN)) { return true; } \
if (a > 0) { \
if (b > 0) { \
if (a > (TMAX) / b) { return true; } \
} else { \
if (b < (TMIN) / a) { return true; } \
} \
} else { \
if (b > 0) { \
if (a < (TMIN) / b) { return true; } \
} else { \
if (a != 0 && b < (TMAX) / a) { return true; } \
} \
} \
*res = a * b; \
return false; \
}
#define R_BUILTIN_MUL_OVFCHK(type, a, b) ({ type _r; __builtin_mul_overflow ((a), (b), &_r); })
R_DEFINE_UNSIGNED_OVERFLOW(ut8, UT8_MAX)
R_DEFINE_UNSIGNED_OVERFLOW(ut16, UT16_MAX)
R_DEFINE_UNSIGNED_OVERFLOW(ut32, UT32_MAX)
R_DEFINE_UNSIGNED_OVERFLOW(ut64, UT64_MAX)
R_DEFINE_UNSIGNED_OVERFLOW(size_t, SIZE_MAX)
static inline bool SZT_MUL_OVFCHK(size_t a, size_t b) { return R_BUILTIN_MUL_OVFCHK (size_t, a, b); }
static inline bool ST8_MUL_OVFCHK(st8 a, st8 b) { return R_BUILTIN_MUL_OVFCHK (st8, a, b); }
static inline bool ST16_MUL_OVFCHK(st16 a, st16 b) { return R_BUILTIN_MUL_OVFCHK (st16, a, b); }
static inline bool ST32_MUL_OVFCHK(st32 a, st32 b) { return R_BUILTIN_MUL_OVFCHK (st32, a, b); }
static inline bool ST64_MUL_OVFCHK(st64 a, st64 b) { return R_BUILTIN_MUL_OVFCHK (st64, a, b); }
static inline bool UT8_MUL_OVFCHK(ut8 a, ut8 b) { return R_BUILTIN_MUL_OVFCHK (ut8, a, b); }
static inline bool UT16_MUL_OVFCHK(ut16 a, ut16 b) { return R_BUILTIN_MUL_OVFCHK (ut16, a, b); }
static inline bool UT32_MUL_OVFCHK(ut32 a, ut32 b) { return R_BUILTIN_MUL_OVFCHK (ut32, a, b); }
static inline bool UT64_MUL_OVFCHK(ut64 a, ut64 b) { return R_BUILTIN_MUL_OVFCHK (ut64, a, b); }
R_DEFINE_SIGNED_OVERFLOW(st8, ST8_MAX, ST8_MIN)
R_DEFINE_SIGNED_OVERFLOW(st16, ST16_MAX, ST16_MIN)
R_DEFINE_SIGNED_OVERFLOW(st32, ST32_MAX, ST32_MIN)
R_DEFINE_SIGNED_OVERFLOW(st64, ST64_MAX, ST64_MIN)
// ssize_t overflow not supported: use st32/st64 instead (MSVC lacks ssize_t)
static inline bool ST8_DIV_OVFCHK(ut8 a, ut8 b) { return (!b || (a == UT8_GT0 && b == UT8_MAX)); }
static inline bool ST16_DIV_OVFCHK(ut16 a, ut16 b) { return (!b || (a == UT16_GT0 && b == UT16_MAX)); }
static inline bool ST32_DIV_OVFCHK(ut32 a, ut32 b) { return (!b || (a == UT32_GT0 && b == UT32_MAX)); }
static inline bool ST64_DIV_OVFCHK(ut64 a, ut64 b) { return (!b || (a == UT64_GT0 && b == UT64_MAX)); }
static inline bool UT8_DIV_OVFCHK(ut8 a, ut8 b) { (void)(a); return !b; }
static inline bool UT16_DIV_OVFCHK(ut16 a, ut16 b) { (void)(a); return !b; }
static inline bool UT32_DIV_OVFCHK(ut32 a, ut32 b) { (void)(a); return !b; }
static inline bool UT64_DIV_OVFCHK(ut64 a, ut64 b) { (void)(a); return !b; }
#if R_HAVE_BUILTIN_OVERFLOW
#define r_add_overflow(a,b,res) __builtin_add_overflow((a),(b),(res))
#define r_sub_overflow(a,b,res) __builtin_sub_overflow((a),(b),(res))
#define r_mul_overflow(a,b,res) __builtin_mul_overflow((a),(b),(res))
#elif defined(_MSC_VER) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
#define r_add_overflow(a,b,res) \
(sizeof(*(res)) == 1 && sizeof(a) == 1 && sizeof(b) == 1 \
? (*(res) = (a) + (b), *(res) < (a)) \
: (sizeof(*(res)) == 2 ? r_add_overflow_ut16((ut16)(a), (ut16)(b), (ut16*)(res)) \
: (sizeof(*(res)) == 4 ? r_add_overflow_ut32((ut32)(a), (ut32)(b), (ut32*)(res)) \
: r_add_overflow_ut64((ut64)(a), (ut64)(b), (ut64*)(res)))))
#define r_sub_overflow(a,b,res) \
(sizeof(*(res)) == 1 && sizeof(a) == 1 && sizeof(b) == 1 \
? (*(res) = (a) - (b), (a) < (b)) \
: (sizeof(*(res)) == 2 ? r_sub_overflow_ut16((ut16)(a), (ut16)(b), (ut16*)(res)) \
: (sizeof(*(res)) == 4 ? r_sub_overflow_ut32((ut32)(a), (ut32)(b), (ut32*)(res)) \
: r_sub_overflow_ut64((ut64)(a), (ut64)(b), (ut64*)(res)))))
#define r_mul_overflow(a,b,res) \
(sizeof(*(res)) == 1 && sizeof(a) == 1 && sizeof(b) == 1 \
? r_mul_overflow_ut8((ut8)(a), (ut8)(b), (ut8*)(res)) \
: (sizeof(*(res)) == 2 ? r_mul_overflow_ut16((ut16)(a), (ut16)(b), (ut16*)(res)) \
: (sizeof(*(res)) == 4 ? r_mul_overflow_ut32((ut32)(a), (ut32)(b), (ut32*)(res)) \
: r_mul_overflow_ut64((ut64)(a), (ut64)(b), (ut64*)(res)))))
#else
#define SZT_ADD_OVFCHK(x,y) ((SIZE_MAX - (x)) < (y))
#define SSZT_ADD_OVFCHK(a,x) ((((x) > 0) && ((a) > SSIZE_MAX - (x))) || (((x) < 0) && ((a) < SSIZE_MIN - (x))))
#define UT64_ADD_OVFCHK(x,y) ((UT64_MAX - (x)) < (y))
#define ST64_ADD_OVFCHK(a,x) ((((x) > 0) && ((a) > ST64_MAX - (x))) || (((x) < 0) && ((a) < ST64_MIN - (x))))
#define UT32_ADD_OVFCHK(x,y) ((UT32_MAX - (x)) < (y))
#define ST32_ADD_OVFCHK(a,x) ((((x) > 0) && ((a) > ST32_MAX - (x))) || (((x) < 0) && ((a) < ST32_MIN - (x))))
#define UT16_ADD_OVFCHK(x,y) (((y) > 0x8000) || ((UT16_MAX - (x)) < (y)))
#define ST16_ADD_OVFCHK(a,b) ((((b) > 0) && ((a) > ST16_MAX - (b))) || (((b) < 0) && ((a) < ST16_MIN - (b))))
#define UT8_ADD_OVFCHK(x,y) ((UT8_MAX - (x)) < (y))
#define ST8_ADD_OVFCHK(a,x) ((((x) > 0) && ((a) > ST8_MAX - (x))) || (((x) < 0) && ((a) < ST8_MIN - (x))))
#define r_add_overflow(a,b,res) _Generic(*(res), \
ut8: r_add_overflow_ut8, \
ut16: r_add_overflow_ut16, \
ut32: r_add_overflow_ut32, \
ut64: r_add_overflow_ut64, \
size_t: r_add_overflow_size_t, \
st8: r_add_overflow_st8, \
st16: r_add_overflow_st16, \
st32: r_add_overflow_st32, \
st64: r_add_overflow_st64 \
)(a,b,res)
#define SZT_SUB_OVFCHK(a,b) SZT_ADD_OVFCHK(a,-(b))
#define SSZT_SUB_OVFCHK(a,b) SSZT_ADD_OVFCHK(a,-(b))
#define UT64_SUB_OVFCHK(a,b) UT64_ADD_OVFCHK(a,(-(st64)(b)))
#define ST64_SUB_OVFCHK(a,b) ST64_ADD_OVFCHK(a,-(b))
#define UT32_SUB_OVFCHK(a,b) UT32_ADD_OVFCHK(a,(-(st32)(b)))
#define ST32_SUB_OVFCHK(a,b) ST32_ADD_OVFCHK(a,-(b))
#define UT16_SUB_OVFCHK(a,b) ((a) < (b))
#define ST16_SUB_OVFCHK(a,b) ST16_ADD_OVFCHK(a,-(b))
#define UT8_SUB_OVFCHK(a,b) UT8_ADD_OVFCHK(a,(-(st8)(b)))
#define ST8_SUB_OVFCHK(a,b) ST8_ADD_OVFCHK(a,-(b))
#define r_sub_overflow(a,b,res) _Generic(*(res), \
ut8: r_sub_overflow_ut8, \
ut16: r_sub_overflow_ut16, \
ut32: r_sub_overflow_ut32, \
ut64: r_sub_overflow_ut64, \
size_t: r_sub_overflow_size_t, \
st8: r_sub_overflow_st8, \
st16: r_sub_overflow_st16, \
st32: r_sub_overflow_st32, \
st64: r_sub_overflow_st64 \
)(a,b,res)
#define UNSIGNED_MUL_OVERFLOW_CHECK(overflow_name, type_base, type_min, type_max) \
static inline bool overflow_name(type_base a, type_base b) { \
return (a > 0 && b > 0 && a > type_max / b); \
}
#define SIGNED_MUL_OVERFLOW_CHECK(overflow_name, type_base, type_min, type_max) \
static inline bool overflow_name(type_base a, type_base b) { \
if (a > 0) { \
if (b > 0) { return a > type_max / b; } \
return b < type_min / a; \
} \
if (b > 0) { return a < type_min / b; } \
return a && b < type_max / a; \
}
#define SIGNED_DIV_OVERFLOW_CHECK(overflow_name, type_base, type_mid, type_max) \
static inline bool overflow_name(type_base a, type_base b) { \
return (!b || (a == type_mid && b == type_max)); \
}
#define UNSIGNED_DIV_OVERFLOW_CHECK(overflow_name, type_base, type_min, type_max) \
static inline bool overflow_name(type_base a, type_base b) { \
(void)(a); \
return !b; \
}
SIGNED_DIV_OVERFLOW_CHECK(ST8_DIV_OVFCHK, ut8, UT8_GT0, UT8_MAX)
SIGNED_DIV_OVERFLOW_CHECK(ST16_DIV_OVFCHK, ut16, UT16_GT0, UT16_MAX)
SIGNED_DIV_OVERFLOW_CHECK(ST32_DIV_OVFCHK, ut32, UT32_GT0, UT32_MAX)
SIGNED_DIV_OVERFLOW_CHECK(ST64_DIV_OVFCHK, ut64, UT64_GT0, UT64_MAX)
UNSIGNED_DIV_OVERFLOW_CHECK(UT8_DIV_OVFCHK, ut8, UT8_MIN, UT8_MAX)
UNSIGNED_DIV_OVERFLOW_CHECK(UT16_DIV_OVFCHK, ut16, UT16_MIN, UT16_MAX)
UNSIGNED_DIV_OVERFLOW_CHECK(UT32_DIV_OVFCHK, ut32, UT32_MIN, UT32_MAX)
UNSIGNED_DIV_OVERFLOW_CHECK(UT64_DIV_OVFCHK, ut64, UT64_MIN, UT64_MAX)
SIGNED_MUL_OVERFLOW_CHECK(ST8_MUL_OVFCHK, st8, ST8_MIN, ST8_MAX)
SIGNED_MUL_OVERFLOW_CHECK(ST16_MUL_OVFCHK, st16, ST16_MIN, ST16_MAX)
SIGNED_MUL_OVERFLOW_CHECK(ST32_MUL_OVFCHK, st32, ST32_MIN, ST32_MAX)
SIGNED_MUL_OVERFLOW_CHECK(ST64_MUL_OVFCHK, st64, ST64_MIN, ST64_MAX)
UNSIGNED_MUL_OVERFLOW_CHECK(SZT_MUL_OVFCHK, size_t, SZT_MIN, SZT_MAX)
UNSIGNED_MUL_OVERFLOW_CHECK(UT8_MUL_OVFCHK, ut8, UT8_MIN, UT8_MAX)
UNSIGNED_MUL_OVERFLOW_CHECK(UT16_MUL_OVFCHK, ut16, UT16_MIN, UT16_MAX)
UNSIGNED_MUL_OVERFLOW_CHECK(UT32_MUL_OVFCHK, ut32, UT32_MIN, UT32_MAX)
UNSIGNED_MUL_OVERFLOW_CHECK(UT64_MUL_OVFCHK, ut64, UT64_MIN, UT64_MAX)
#define r_mul_overflow(a,b,res) _Generic(*(res), \
ut8: r_mul_overflow_ut8, \
ut16: r_mul_overflow_ut16, \
ut32: r_mul_overflow_ut32, \
ut64: r_mul_overflow_ut64, \
size_t: r_mul_overflow_size_t, \
st8: r_mul_overflow_st8, \
st16: r_mul_overflow_st16, \
st32: r_mul_overflow_st32, \
st64: r_mul_overflow_st64 \
)(a,b,res)
#endif
static inline bool r_div_overflow_st8(st8 a, st8 b) { return (!b || (a == ST8_MIN && b == -1)); }
static inline bool r_div_overflow_st16(st16 a, st16 b) { return (!b || (a == ST16_MIN && b == -1)); }
static inline bool r_div_overflow_st32(st32 a, st32 b) { return (!b || (a == ST32_MIN && b == -1)); }
static inline bool r_div_overflow_st64(st64 a, st64 b) { return (!b || (a == ST64_MIN && b == -1)); }
static inline bool r_div_overflow_ut8(ut8 a, ut8 b) { (void)(a); return !b; }
static inline bool r_div_overflow_ut16(ut16 a, ut16 b) { (void)(a); return !b; }
static inline bool r_div_overflow_ut32(ut32 a, ut32 b) { (void)(a); return !b; }
static inline bool r_div_overflow_ut64(ut64 a, ut64 b) { (void)(a); return !b; }
#ifdef __cplusplus
}
#endif

View file

@ -151,10 +151,11 @@ extern "C" {
// Overflow-safe realloc wrapper (like reallocarray)
static inline void *r_vec_realloc(void *ptr, size_t nmemb, size_t size) {
if (SZT_MUL_OVFCHK (nmemb, size)) {
size_t total;
if (r_mul_overflow (nmemb, size, &total)) {
return NULL;
}
return realloc (ptr, nmemb * size);
return realloc (ptr, total);
}
// Overflow-safe capacity growth (returns 0 on overflow)
@ -162,10 +163,11 @@ static inline size_t r_vec_grow(size_t capacity) {
if (capacity == 0) {
return 8;
}
if (SZT_MUL_OVFCHK (capacity, 2)) {
size_t new_capacity;
if (r_mul_overflow (capacity, (size_t)2, &new_capacity)) {
return 0;
}
return capacity * 2;
return new_capacity;
}
// Hack / Helper macro for conditional code generation.
@ -297,11 +299,11 @@ static inline size_t r_vec_grow(size_t capacity) {
static inline R_MAYBE_UNUSED R_MUSTUSE vec_type *R_VEC_FUNC(vec_type, clone)(const vec_type *vec) { \
R_RETURN_VAL_IF_FAIL (vec, NULL); \
const size_t capacity = R_VEC_CAPACITY (vec); \
if (SZT_MUL_OVFCHK (capacity, sizeof (type))) { \
size_t alloc_size; \
if (r_mul_overflow (capacity, sizeof (type), &alloc_size)) { \
return NULL; \
} \
size_t new_capacity = capacity * sizeof (type); \
type *buf = (type *)malloc (new_capacity); \
type *buf = (type *)malloc (alloc_size); \
if (R_LIKELY (buf)) { \
vec_type *cloned_vec = (vec_type *)malloc (sizeof (vec_type)); \
if (R_LIKELY (cloned_vec)) { \

View file

@ -4,12 +4,12 @@
#include <r_util.h>
static ut8 *r_rap_packet(ut8 type, ut32 len) {
/* Prevent size overflow in allocation */
if (SZT_ADD_OVFCHK ((size_t)len, 5)) {
size_t alloc_size;
if (r_add_overflow ((size_t)len, (size_t)5, &alloc_size)) {
R_LOG_ERROR ("rap: packet length overflow %u", len);
return NULL;
}
ut8 *buf = malloc (len + 5);
ut8 *buf = malloc (alloc_size);
if (buf) {
buf[0] = type;
r_write_be32 (buf + 1, len);

View file

@ -487,11 +487,11 @@ R_API bool r_bplist_parse(PJ *pj, const ut8 *data, size_t data_len) {
R_LOG_ERROR ("offset table offset points outside of valid range");
return false;
}
if (UT64_MUL_OVFCHK (num_objects, offset_size)) {
ut64 offset_table_size;
if (r_mul_overflow (num_objects, offset_size, &offset_table_size)) {
R_LOG_ERROR ("integer overflow when calculating offset table size");
return false;
}
ut64 offset_table_size = num_objects * offset_size;
if (offset_table_size > (ut64)(end_data - offset_table)) {
R_LOG_ERROR ("offset table points outside of valid range");
return false;

View file

@ -1869,8 +1869,9 @@ R_API int r_print_format_sizeof(RPrint *p, const char *f, int mode, int n) {
ret = 0;
goto cleanup_struct;
}
if (!ST32_MUL_OVFCHK (tabsize, newsize)) {
size = size + (tabsize * newsize);
st32 mul_result;
if (!r_mul_overflow (tabsize, newsize, &mul_result)) {
size = size + mul_result;
} else {
R_LOG_ERROR ("Prevented multiply integer overflow in format2.c");
ret = 0;

View file

@ -155,11 +155,12 @@ static char *decode_buffer(PJ *pj, const ut8* start, const ut8* end, int padcnt,
R_LOG_ERROR ("Invalid delta in var64");
goto leave;
}
if (UT64_ADD_OVFCHK ((size_t)ps, var64)) {
size_t pe_addr;
if (r_add_overflow ((size_t)ps, (size_t)var64, &pe_addr)) {
R_LOG_ERROR ("Invalid overflow in var64");
goto leave;
}
const ut8* pe = (const ut8*)ps + var64;
const ut8* pe = (const ut8*)pe_addr;
if (ps > buffer && pe <= end) {
if (is_string (ps, pe)) {
if (mode == 'J') {

View file

@ -1740,10 +1740,10 @@ R_API char *r_str_encoded_json(const char *buf, int buf_size, int encoding) {
size_t i = 0;
size_t increment = encoding == PJ_ENCODING_STR_ARRAY? 4: 2;
if (!SZT_MUL_OVFCHK (((buf_sz * increment) + 1), SZT_MAX)) {
size_t new_sz;
if (r_mul_overflow (buf_sz, increment, &new_sz) || r_add_overflow (new_sz, (size_t)1, &new_sz)) {
return NULL;
}
size_t new_sz = (buf_sz * increment) + 1;
encoded_str = malloc (new_sz);
if (!encoded_str) {

View file

@ -261,11 +261,10 @@ R_API bool r_strbuf_append_n(RStrBuf *sb, const char *s, size_t l) {
return false;
}
if (SZT_ADD_OVFCHK (sb->len, l + 1)) {
size_t required;
if (r_add_overflow (sb->len, l + 1, &required)) {
return false;
}
size_t required = sb->len + l + 1;
if (sb->weakref || l == 0) {
return !sb->weakref;
}

View file

@ -802,9 +802,10 @@ R_API void r_table_filter(RTable *t, int nth, int op, const char *un) {
if (page < 1) {
page = 1;
}
if (!ST32_MUL_OVFCHK (page, page_items)) {
lrow = page_items * (page - 1);
uv = ((ut64)page_items) * page;
st32 page_offset;
if (!r_mul_overflow (page_items, page - 1, &page_offset)) {
lrow = page_offset;
uv = (ut64)page_offset + (ut64)page_items;
} else {
uv = 0;
}

View file

@ -71,13 +71,17 @@ static ut64 base36_decode(const char *str) {
}
v -= 91;
// Check for overflow
if (i == 12) {
if (v > 3 || UT64_ADD_OVFCHK (ret, v * pow36[i])) {
printf ("Error: base36_decode supports up to 64-bit values only\n");
return 0;
}
ut64 term = v * pow36[i];
ut64 new_ret;
if (i == 12 && (v > 3 || r_add_overflow (ret, term, &new_ret))) {
printf ("Error: base36_decode supports up to 64-bit values only\n");
return 0;
}
ret += v * pow36[i];
if (r_add_overflow (ret, term, &new_ret)) {
printf ("Error: base36_decode overflow\n");
return 0;
}
ret = new_ret;
}
return ret;
}

View file

@ -1,71 +1,459 @@
/* radare2 - LGPL - Copyright 2020 - pancake */
/* radare2 - LGPL - Copyright 2020-2026 - pancake */
#include <r_util.h>
#include "minunit.h"
int test_overflow_add(void) {
mu_assert_true (UT8_ADD_OVFCHK (250, 32), "ut8-add 1");
mu_assert_false (UT8_ADD_OVFCHK (250, 2), "ut8-add 2");
mu_assert_false (UT16_ADD_OVFCHK (ST16_MAX, 2), "ut16-add 2");
mu_assert_true (ST16_ADD_OVFCHK (ST16_MAX, 2), "st16-add 2");
mu_assert_true (ST16_ADD_OVFCHK (ST16_MAX - 2, 4), "st16-add 2");
mu_assert_true (ST16_ADD_OVFCHK (1, ST16_MAX), "st16-add 3");
mu_assert_true (ST16_ADD_OVFCHK (ST16_MIN, (st16)-1), "st16-add (min, -1)");
mu_assert_true (UT16_ADD_OVFCHK (10, (ut16)-20), "ut16-add (10, -20)");
mu_assert_false (ST16_ADD_OVFCHK ((st16)-10, 20), "st16-add (-10, 20)");
mu_assert_true (ST32_ADD_OVFCHK (ST32_MIN, -20), "st32-add (min, -20)");
mu_assert_false (ST32_ADD_OVFCHK ((st32)-10, 20), "st32-add (-10, 20)");
mu_assert_true (ST64_ADD_OVFCHK (ST64_MIN, -20), "st64-add (min, -20)");
mu_assert_false (ST64_ADD_OVFCHK ((st64)-10, 20), "st64-add 3");
int test_ut8_add_overflow(void) {
ut8 res;
mu_assert_true (r_add_overflow_ut8 (250, 32, &res), "ut8 add overflow: 250+32");
mu_assert_false (r_add_overflow_ut8 (250, 5, &res), "ut8 add no overflow: 250+5");
mu_assert_eq (res, 255, "ut8 add result: 250+5=255");
mu_assert_false (r_add_overflow_ut8 (0, 0, &res), "ut8 add: 0+0");
mu_assert_eq (res, 0, "ut8 add result: 0+0=0");
mu_assert_false (r_add_overflow_ut8 (100, 50, &res), "ut8 add: 100+50");
mu_assert_eq (res, 150, "ut8 add result: 100+50=150");
mu_assert_true (r_add_overflow_ut8 (UT8_MAX, 1, &res), "ut8 add overflow: max+1");
mu_assert_false (r_add_overflow_ut8 (UT8_MAX, 0, &res), "ut8 add: max+0");
mu_assert_eq (res, UT8_MAX, "ut8 add result: max+0=max");
mu_end;
}
int test_underflow_sub(void) {
mu_assert_false (ST16_SUB_OVFCHK (10, 210), "st16-sub-sign-underflow");
mu_assert_true (UT16_SUB_OVFCHK (10, 210), "ut16-sub-underflow");
mu_assert_true (ST16_SUB_OVFCHK (ST16_MIN, 210), "st16-sub-underflow");
int test_st8_add_overflow(void) {
st8 res;
mu_assert_true (r_add_overflow_st8 (ST8_MAX, 1, &res), "st8 add overflow: max+1");
mu_assert_false (r_add_overflow_st8 (ST8_MAX, 0, &res), "st8 add: max+0");
mu_assert_eq (res, ST8_MAX, "st8 add result: max+0=max");
mu_assert_true (r_add_overflow_st8 (ST8_MIN, -1, &res), "st8 add underflow: min-1");
mu_assert_false (r_add_overflow_st8 (ST8_MIN, 0, &res), "st8 add: min+0");
mu_assert_eq (res, ST8_MIN, "st8 add result: min+0=min");
mu_assert_false (r_add_overflow_st8 (-50, 100, &res), "st8 add: -50+100");
mu_assert_eq (res, 50, "st8 add result: -50+100=50");
mu_assert_false (r_add_overflow_st8 (50, -100, &res), "st8 add: 50-100");
mu_assert_eq (res, -50, "st8 add result: 50-100=-50");
mu_assert_false (r_add_overflow_st8 (-10, 20, &res), "st8 add: -10+20");
mu_assert_eq (res, 10, "st8 add result: -10+20=10");
mu_end;
}
int test_underflow_add(void) {
mu_assert_false (ST16_SUB_OVFCHK (10, (st16)-210), "st16-sub");
mu_assert_false (ST16_SUB_OVFCHK (10, 10), "st16-sub 10");
mu_assert_true (ST16_SUB_OVFCHK (ST16_MIN, 11), "st16-sub 10-11");
mu_assert_false (ST16_SUB_OVFCHK (10, 11), "st16-sub 10-11");
mu_assert_true (UT16_SUB_OVFCHK (10, 11), "ut16-sub 10-11");
int test_ut16_add_overflow(void) {
ut16 res;
mu_assert_false (r_add_overflow_ut16 (ST16_MAX, 2, &res), "ut16 add: st16_max+2 fits in ut16");
mu_assert_eq (res, (ut16)ST16_MAX + 2, "ut16 add result correct");
mu_assert_true (r_add_overflow_ut16 (UT16_MAX, 1, &res), "ut16 add overflow: max+1");
mu_assert_false (r_add_overflow_ut16 (0, UT16_MAX, &res), "ut16 add: 0+max");
mu_assert_eq (res, UT16_MAX, "ut16 add result: 0+max=max");
mu_assert_true (r_add_overflow_ut16 (UT16_MAX - 10, 20, &res), "ut16 add overflow: near max");
mu_end;
}
int test_overflow_mul(void) {
mu_assert_true (UT8_MUL_OVFCHK (16, 32), "ut8-mul");
mu_assert_false (UT8_MUL_OVFCHK (16, 2), "ut8-mul 2");
mu_assert_true (ST8_MUL_OVFCHK (16, 100), "st8-mul 3");
mu_assert_false (ST8_MUL_OVFCHK (16, 1), "st8-mul 4");
mu_assert_false (ST8_MUL_OVFCHK (-2, 2), "st8-mul sign overflow");
mu_assert_false (ST8_MUL_OVFCHK (-1, 1), "st8-mul sign overflow");
mu_assert_false (ST8_MUL_OVFCHK (1, -1), "st8-mul sign overflow");
mu_assert_false (ST8_MUL_OVFCHK (2, -2), "st8-mul sign overflow");
mu_assert_false (ST8_MUL_OVFCHK (-1, -2), "st8-mul sign overflow");
mu_assert_false (ST8_MUL_OVFCHK (-2, -1), "st8-mul sign overflow");
mu_assert_true (ST8_MUL_OVFCHK (-16, 100), "st8-mul sign overflow");
mu_assert_true (ST8_MUL_OVFCHK (100, -16), "st8-mul sign overflow");
mu_assert_false (ST8_MUL_OVFCHK (3, -16), "st8-mul sign overflow");
int test_st16_add_overflow(void) {
st16 res;
mu_assert_true (r_add_overflow_st16 (ST16_MAX, 2, &res), "st16 add overflow: max+2");
mu_assert_true (r_add_overflow_st16 (ST16_MAX - 2, 4, &res), "st16 add overflow: max-2+4");
mu_assert_true (r_add_overflow_st16 (1, ST16_MAX, &res), "st16 add overflow: 1+max");
mu_assert_true (r_add_overflow_st16 (ST16_MIN, -1, &res), "st16 add underflow: min-1");
mu_assert_false (r_add_overflow_st16 (-10, 20, &res), "st16 add: -10+20");
mu_assert_eq (res, 10, "st16 add result: -10+20=10");
mu_assert_false (r_add_overflow_st16 (0, 0, &res), "st16 add: 0+0");
mu_assert_eq (res, 0, "st16 add result: 0+0=0");
mu_end;
}
int test_overflow_mul2(void) {
mu_assert_false (ST8_MUL_OVFCHK (-1, 0), "st8-mul2 -1 0");
mu_assert_false (ST8_MUL_OVFCHK (1, 0), "st8-mul2 -1 0");
int test_ut32_add_overflow(void) {
ut32 res;
mu_assert_true (r_add_overflow_ut32 (UT32_MAX, 1, &res), "ut32 add overflow: max+1");
mu_assert_false (r_add_overflow_ut32 (UT32_MAX, 0, &res), "ut32 add: max+0");
mu_assert_eq (res, UT32_MAX, "ut32 add result: max+0=max");
mu_assert_false (r_add_overflow_ut32 (1000000, 2000000, &res), "ut32 add: 1M+2M");
mu_assert_eq (res, 3000000, "ut32 add result: 1M+2M=3M");
mu_end;
}
int test_st32_add_overflow(void) {
st32 res;
mu_assert_true (r_add_overflow_st32 (ST32_MAX, 1, &res), "st32 add overflow: max+1");
mu_assert_true (r_add_overflow_st32 (ST32_MIN, -1, &res), "st32 add underflow: min-1");
mu_assert_true (r_add_overflow_st32 (ST32_MIN, -20, &res), "st32 add underflow: min-20");
mu_assert_false (r_add_overflow_st32 (-10, 20, &res), "st32 add: -10+20");
mu_assert_eq (res, 10, "st32 add result: -10+20=10");
mu_end;
}
int test_ut64_add_overflow(void) {
ut64 res;
mu_assert_true (r_add_overflow_ut64 (UT64_MAX, 1, &res), "ut64 add overflow: max+1");
mu_assert_false (r_add_overflow_ut64 (UT64_MAX, 0, &res), "ut64 add: max+0");
mu_assert_eq (res, UT64_MAX, "ut64 add result: max+0=max");
mu_assert_false (r_add_overflow_ut64 (1, 1, &res), "ut64 add: 1+1");
mu_assert_eq (res, 2, "ut64 add result: 1+1=2");
mu_end;
}
int test_st64_add_overflow(void) {
st64 res;
mu_assert_true (r_add_overflow_st64 (ST64_MAX, 1, &res), "st64 add overflow: max+1");
mu_assert_true (r_add_overflow_st64 (ST64_MIN, -1, &res), "st64 add underflow: min-1");
mu_assert_true (r_add_overflow_st64 (ST64_MIN, -20, &res), "st64 add underflow: min-20");
mu_assert_false (r_add_overflow_st64 (-10, 20, &res), "st64 add: -10+20");
mu_assert_eq (res, 10, "st64 add result: -10+20=10");
mu_end;
}
int test_ut8_sub_overflow(void) {
ut8 res;
mu_assert_true (r_sub_overflow_ut8 (10, 20, &res), "ut8 sub underflow: 10-20");
mu_assert_false (r_sub_overflow_ut8 (20, 10, &res), "ut8 sub: 20-10");
mu_assert_eq (res, 10, "ut8 sub result: 20-10=10");
mu_assert_false (r_sub_overflow_ut8 (0, 0, &res), "ut8 sub: 0-0");
mu_assert_eq (res, 0, "ut8 sub result: 0-0=0");
mu_assert_true (r_sub_overflow_ut8 (0, 1, &res), "ut8 sub underflow: 0-1");
mu_end;
}
int test_st8_sub_overflow(void) {
st8 res;
mu_assert_false (r_sub_overflow_st8 (10, 20, &res), "st8 sub: 10-20");
mu_assert_eq (res, -10, "st8 sub result: 10-20=-10");
mu_assert_true (r_sub_overflow_st8 (ST8_MIN, 1, &res), "st8 sub underflow: min-1");
mu_assert_true (r_sub_overflow_st8 (ST8_MAX, -1, &res), "st8 sub overflow: max-(-1)");
mu_assert_false (r_sub_overflow_st8 (-10, -20, &res), "st8 sub: -10-(-20)");
mu_assert_eq (res, 10, "st8 sub result: -10-(-20)=10");
mu_end;
}
int test_ut16_sub_overflow(void) {
ut16 res;
mu_assert_true (r_sub_overflow_ut16 (10, 210, &res), "ut16 sub underflow: 10-210");
mu_assert_true (r_sub_overflow_ut16 (10, 11, &res), "ut16 sub underflow: 10-11");
mu_assert_false (r_sub_overflow_ut16 (11, 10, &res), "ut16 sub: 11-10");
mu_assert_eq (res, 1, "ut16 sub result: 11-10=1");
mu_assert_false (r_sub_overflow_ut16 (10, 10, &res), "ut16 sub: 10-10");
mu_assert_eq (res, 0, "ut16 sub result: 10-10=0");
mu_end;
}
int test_st16_sub_overflow(void) {
st16 res;
mu_assert_false (r_sub_overflow_st16 (10, 210, &res), "st16 sub: 10-210 (signed ok)");
mu_assert_eq (res, -200, "st16 sub result: 10-210=-200");
mu_assert_true (r_sub_overflow_st16 (ST16_MIN, 210, &res), "st16 sub underflow: min-210");
mu_assert_false (r_sub_overflow_st16 (10, -210, &res), "st16 sub: 10-(-210)");
mu_assert_eq (res, 220, "st16 sub result: 10-(-210)=220");
mu_assert_false (r_sub_overflow_st16 (10, 10, &res), "st16 sub: 10-10");
mu_assert_eq (res, 0, "st16 sub result: 10-10=0");
mu_assert_true (r_sub_overflow_st16 (ST16_MIN, 11, &res), "st16 sub underflow: min-11");
mu_assert_false (r_sub_overflow_st16 (10, 11, &res), "st16 sub: 10-11");
mu_assert_eq (res, -1, "st16 sub result: 10-11=-1");
mu_end;
}
int test_ut8_mul_overflow(void) {
ut8 res;
mu_assert_true (r_mul_overflow_ut8 (16, 32, &res), "ut8 mul overflow: 16*32");
mu_assert_false (r_mul_overflow_ut8 (16, 2, &res), "ut8 mul: 16*2");
mu_assert_eq (res, 32, "ut8 mul result: 16*2=32");
mu_assert_false (r_mul_overflow_ut8 (0, 255, &res), "ut8 mul: 0*255");
mu_assert_eq (res, 0, "ut8 mul result: 0*255=0");
mu_assert_false (r_mul_overflow_ut8 (1, 255, &res), "ut8 mul: 1*255");
mu_assert_eq (res, 255, "ut8 mul result: 1*255=255");
mu_assert_true (r_mul_overflow_ut8 (2, 200, &res), "ut8 mul overflow: 2*200");
mu_end;
}
int test_st8_mul_overflow(void) {
st8 res;
mu_assert_true (r_mul_overflow_st8 (16, 100, &res), "st8 mul overflow: 16*100");
mu_assert_false (r_mul_overflow_st8 (16, 1, &res), "st8 mul: 16*1");
mu_assert_eq (res, 16, "st8 mul result: 16*1=16");
mu_assert_false (r_mul_overflow_st8 (-2, 2, &res), "st8 mul: -2*2");
mu_assert_eq (res, -4, "st8 mul result: -2*2=-4");
mu_assert_false (r_mul_overflow_st8 (-1, 1, &res), "st8 mul: -1*1");
mu_assert_eq (res, -1, "st8 mul result: -1*1=-1");
mu_assert_false (r_mul_overflow_st8 (1, -1, &res), "st8 mul: 1*-1");
mu_assert_eq (res, -1, "st8 mul result: 1*-1=-1");
mu_assert_false (r_mul_overflow_st8 (2, -2, &res), "st8 mul: 2*-2");
mu_assert_eq (res, -4, "st8 mul result: 2*-2=-4");
mu_assert_false (r_mul_overflow_st8 (-1, -2, &res), "st8 mul: -1*-2");
mu_assert_eq (res, 2, "st8 mul result: -1*-2=2");
mu_assert_false (r_mul_overflow_st8 (-2, -1, &res), "st8 mul: -2*-1");
mu_assert_eq (res, 2, "st8 mul result: -2*-1=2");
mu_assert_true (r_mul_overflow_st8 (-16, 100, &res), "st8 mul overflow: -16*100");
mu_assert_true (r_mul_overflow_st8 (100, -16, &res), "st8 mul overflow: 100*-16");
mu_assert_false (r_mul_overflow_st8 (3, -16, &res), "st8 mul: 3*-16");
mu_assert_eq (res, -48, "st8 mul result: 3*-16=-48");
mu_assert_false (r_mul_overflow_st8 (-1, 0, &res), "st8 mul: -1*0");
mu_assert_eq (res, 0, "st8 mul result: -1*0=0");
mu_assert_false (r_mul_overflow_st8 (1, 0, &res), "st8 mul: 1*0");
mu_assert_eq (res, 0, "st8 mul result: 1*0=0");
mu_assert_true (r_mul_overflow_st8 (ST8_MIN, -1, &res), "st8 mul overflow: min*-1");
mu_end;
}
int test_ut16_mul_overflow(void) {
ut16 res;
mu_assert_true (r_mul_overflow_ut16 (1000, 1000, &res), "ut16 mul overflow: 1000*1000");
mu_assert_false (r_mul_overflow_ut16 (100, 100, &res), "ut16 mul: 100*100");
mu_assert_eq (res, 10000, "ut16 mul result: 100*100=10000");
mu_assert_false (r_mul_overflow_ut16 (0, UT16_MAX, &res), "ut16 mul: 0*max");
mu_assert_eq (res, 0, "ut16 mul result: 0*max=0");
mu_end;
}
int test_st16_mul_overflow(void) {
st16 res;
mu_assert_true (r_mul_overflow_st16 (ST16_MIN, -1, &res), "st16 mul overflow: min*-1");
mu_assert_false (r_mul_overflow_st16 (100, -100, &res), "st16 mul: 100*-100");
mu_assert_eq (res, -10000, "st16 mul result: 100*-100=-10000");
mu_assert_true (r_mul_overflow_st16 (ST16_MAX, 2, &res), "st16 mul overflow: max*2");
mu_end;
}
int test_ut32_mul_overflow(void) {
ut32 res;
mu_assert_true (r_mul_overflow_ut32 (UT32_MAX, 2, &res), "ut32 mul overflow: max*2");
mu_assert_false (r_mul_overflow_ut32 (1000, 1000, &res), "ut32 mul: 1000*1000");
mu_assert_eq (res, 1000000, "ut32 mul result: 1000*1000=1000000");
mu_assert_false (r_mul_overflow_ut32 (0, UT32_MAX, &res), "ut32 mul: 0*max");
mu_assert_eq (res, 0, "ut32 mul result: 0*max=0");
mu_end;
}
int test_st32_mul_overflow(void) {
st32 res;
mu_assert_true (r_mul_overflow_st32 (ST32_MIN, -1, &res), "st32 mul overflow: min*-1");
mu_assert_false (r_mul_overflow_st32 (1000, -1000, &res), "st32 mul: 1000*-1000");
mu_assert_eq (res, -1000000, "st32 mul result: 1000*-1000=-1000000");
mu_assert_true (r_mul_overflow_st32 (ST32_MAX, 2, &res), "st32 mul overflow: max*2");
mu_end;
}
int test_ut64_mul_overflow(void) {
ut64 res;
mu_assert_true (r_mul_overflow_ut64 (UT64_MAX, 2, &res), "ut64 mul overflow: max*2");
mu_assert_false (r_mul_overflow_ut64 (1000000, 1000000, &res), "ut64 mul: 1M*1M");
mu_assert_eq (res, 1000000000000ULL, "ut64 mul result: 1M*1M=1T");
mu_assert_false (r_mul_overflow_ut64 (0, UT64_MAX, &res), "ut64 mul: 0*max");
mu_assert_eq (res, 0, "ut64 mul result: 0*max=0");
mu_end;
}
int test_st64_mul_overflow(void) {
st64 res;
mu_assert_true (r_mul_overflow_st64 (ST64_MIN, -1, &res), "st64 mul overflow: min*-1");
mu_assert_false (r_mul_overflow_st64 (1000000, -1000000, &res), "st64 mul: 1M*-1M");
mu_assert_eq (res, -1000000000000LL, "st64 mul result: 1M*-1M=-1T");
mu_assert_true (r_mul_overflow_st64 (ST64_MAX, 2, &res), "st64 mul overflow: max*2");
mu_end;
}
int test_ut8_div_overflow(void) {
mu_assert_true (r_div_overflow_ut8 (100, 0), "ut8 div by zero");
mu_assert_false (r_div_overflow_ut8 (100, 1), "ut8 div: 100/1");
mu_assert_false (r_div_overflow_ut8 (0, 1), "ut8 div: 0/1");
mu_end;
}
int test_st8_div_overflow(void) {
mu_assert_true (r_div_overflow_st8 (100, 0), "st8 div by zero");
mu_assert_true (r_div_overflow_st8 (ST8_MIN, -1), "st8 div overflow: min/-1");
mu_assert_false (r_div_overflow_st8 (ST8_MAX, -1), "st8 div: max/-1");
mu_assert_false (r_div_overflow_st8 (-100, 1), "st8 div: -100/1");
mu_end;
}
int test_ut16_div_overflow(void) {
mu_assert_true (r_div_overflow_ut16 (100, 0), "ut16 div by zero");
mu_assert_false (r_div_overflow_ut16 (100, 1), "ut16 div: 100/1");
mu_end;
}
int test_st16_div_overflow(void) {
mu_assert_true (r_div_overflow_st16 (100, 0), "st16 div by zero");
mu_assert_true (r_div_overflow_st16 (ST16_MIN, -1), "st16 div overflow: min/-1");
mu_assert_false (r_div_overflow_st16 (ST16_MAX, -1), "st16 div: max/-1");
mu_end;
}
int test_ut32_div_overflow(void) {
mu_assert_true (r_div_overflow_ut32 (100, 0), "ut32 div by zero");
mu_assert_false (r_div_overflow_ut32 (100, 1), "ut32 div: 100/1");
mu_end;
}
int test_st32_div_overflow(void) {
mu_assert_true (r_div_overflow_st32 (100, 0), "st32 div by zero");
mu_assert_true (r_div_overflow_st32 (ST32_MIN, -1), "st32 div overflow: min/-1");
mu_assert_false (r_div_overflow_st32 (ST32_MAX, -1), "st32 div: max/-1");
mu_end;
}
int test_ut64_div_overflow(void) {
mu_assert_true (r_div_overflow_ut64 (100, 0), "ut64 div by zero");
mu_assert_false (r_div_overflow_ut64 (100, 1), "ut64 div: 100/1");
mu_end;
}
int test_st64_div_overflow(void) {
mu_assert_true (r_div_overflow_st64 (100, 0), "st64 div by zero");
mu_assert_true (r_div_overflow_st64 (ST64_MIN, -1), "st64 div overflow: min/-1");
mu_assert_false (r_div_overflow_st64 (ST64_MAX, -1), "st64 div: max/-1");
mu_end;
}
int test_size_t_add_overflow(void) {
size_t res;
mu_assert_true (r_add_overflow_size_t (SIZE_MAX, 1, &res), "size_t add overflow: max+1");
mu_assert_false (r_add_overflow_size_t (SIZE_MAX, 0, &res), "size_t add: max+0");
mu_assert_eq (res, SIZE_MAX, "size_t add result: max+0=max");
mu_assert_false (r_add_overflow_size_t (100, 200, &res), "size_t add: 100+200");
mu_assert_eq (res, 300, "size_t add result: 100+200=300");
mu_end;
}
int test_size_t_sub_overflow(void) {
size_t res;
mu_assert_true (r_sub_overflow_size_t (10, 20, &res), "size_t sub underflow: 10-20");
mu_assert_false (r_sub_overflow_size_t (20, 10, &res), "size_t sub: 20-10");
mu_assert_eq (res, 10, "size_t sub result: 20-10=10");
mu_assert_false (r_sub_overflow_size_t (0, 0, &res), "size_t sub: 0-0");
mu_assert_eq (res, 0, "size_t sub result: 0-0=0");
mu_end;
}
int test_size_t_mul_overflow(void) {
size_t res;
mu_assert_true (r_mul_overflow_size_t (SIZE_MAX, 2, &res), "size_t mul overflow: max*2");
mu_assert_false (r_mul_overflow_size_t (1000, 1000, &res), "size_t mul: 1000*1000");
mu_assert_eq (res, 1000000, "size_t mul result: 1000*1000=1000000");
mu_assert_false (r_mul_overflow_size_t (0, SIZE_MAX, &res), "size_t mul: 0*max");
mu_assert_eq (res, 0, "size_t mul result: 0*max=0");
mu_end;
}
int test_boundary_signed_unsigned(void) {
ut8 ures8;
st8 sres8;
ut16 ures16;
st16 sres16;
ut32 ures32;
st32 sres32;
ut64 ures64;
st64 sres64;
mu_assert_false (r_add_overflow_ut8 (127, 1, &ures8), "ut8 can hold 128");
mu_assert_eq (ures8, 128, "ut8 128 correct");
mu_assert_true (r_add_overflow_st8 (127, 1, &sres8), "st8 overflow at 128");
mu_assert_false (r_add_overflow_ut16 (32767, 1, &ures16), "ut16 can hold 32768");
mu_assert_eq (ures16, 32768, "ut16 32768 correct");
mu_assert_true (r_add_overflow_st16 (32767, 1, &sres16), "st16 overflow at 32768");
mu_assert_false (r_add_overflow_ut32 (2147483647, 1, &ures32), "ut32 can hold 2147483648");
mu_assert_eq (ures32, 2147483648U, "ut32 2147483648 correct");
mu_assert_true (r_add_overflow_st32 (2147483647, 1, &sres32), "st32 overflow at 2147483648");
mu_assert_false (r_add_overflow_ut64 (9223372036854775807ULL, 1, &ures64), "ut64 can hold max st64 + 1");
mu_assert_true (r_add_overflow_st64 (9223372036854775807LL, 1, &sres64), "st64 overflow at max+1");
mu_end;
}
int test_negative_boundary(void) {
st8 sres8;
st16 sres16;
st32 sres32;
st64 sres64;
mu_assert_false (r_sub_overflow_st8 (-127, 1, &sres8), "st8 can hold -128");
mu_assert_eq (sres8, ST8_MIN, "st8 min correct");
mu_assert_true (r_sub_overflow_st8 (ST8_MIN, 1, &sres8), "st8 underflow at min-1");
mu_assert_false (r_sub_overflow_st16 (-32767, 1, &sres16), "st16 can hold -32768");
mu_assert_eq (sres16, ST16_MIN, "st16 min correct");
mu_assert_true (r_sub_overflow_st16 (ST16_MIN, 1, &sres16), "st16 underflow at min-1");
mu_assert_false (r_sub_overflow_st32 (-2147483647, 1, &sres32), "st32 can hold min");
mu_assert_eq (sres32, ST32_MIN, "st32 min correct");
mu_assert_true (r_sub_overflow_st32 (ST32_MIN, 1, &sres32), "st32 underflow at min-1");
mu_assert_false (r_sub_overflow_st64 (-9223372036854775807LL, 1, &sres64), "st64 can hold min");
mu_assert_eq (sres64, ST64_MIN, "st64 min correct");
mu_assert_true (r_sub_overflow_st64 (ST64_MIN, 1, &sres64), "st64 underflow at min-1");
mu_end;
}
#if R_HAVE_BUILTIN_OVERFLOW || (!defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
int test_generic_overflow(void) {
ut8 ures8;
ut16 ures16;
ut32 ures32;
ut64 ures64;
mu_assert_true (r_add_overflow (UT8_MAX, 1, &ures8), "generic ut8 add overflow");
mu_assert_false (r_add_overflow (100, 50, &ures8), "generic ut8 add no overflow");
mu_assert_eq (ures8, 150, "generic ut8 add result correct");
mu_assert_true (r_sub_overflow (10, 20, &ures8), "generic ut8 sub underflow");
mu_assert_false (r_sub_overflow (20, 10, &ures8), "generic ut8 sub no underflow");
mu_assert_eq (ures8, 10, "generic ut8 sub result correct");
mu_assert_true (r_mul_overflow (UT8_MAX, 2, &ures8), "generic ut8 mul overflow");
mu_assert_false (r_mul_overflow (10, 10, &ures8), "generic ut8 mul no overflow");
mu_assert_eq (ures8, 100, "generic ut8 mul result correct");
mu_assert_true (r_add_overflow (UT16_MAX, 1, &ures16), "generic ut16 add overflow");
mu_assert_true (r_add_overflow (UT32_MAX, 1, &ures32), "generic ut32 add overflow");
mu_assert_true (r_add_overflow (UT64_MAX, 1, &ures64), "generic ut64 add overflow");
mu_end;
}
#endif
int all_tests(void) {
mu_run_test (test_overflow_add);
mu_run_test (test_underflow_add);
mu_run_test (test_underflow_sub);
mu_run_test (test_overflow_mul);
mu_run_test (test_overflow_mul2);
mu_run_test (test_ut8_add_overflow);
mu_run_test (test_st8_add_overflow);
mu_run_test (test_ut16_add_overflow);
mu_run_test (test_st16_add_overflow);
mu_run_test (test_ut32_add_overflow);
mu_run_test (test_st32_add_overflow);
mu_run_test (test_ut64_add_overflow);
mu_run_test (test_st64_add_overflow);
mu_run_test (test_ut8_sub_overflow);
mu_run_test (test_st8_sub_overflow);
mu_run_test (test_ut16_sub_overflow);
mu_run_test (test_st16_sub_overflow);
mu_run_test (test_ut8_mul_overflow);
mu_run_test (test_st8_mul_overflow);
mu_run_test (test_ut16_mul_overflow);
mu_run_test (test_st16_mul_overflow);
mu_run_test (test_ut32_mul_overflow);
mu_run_test (test_st32_mul_overflow);
mu_run_test (test_ut64_mul_overflow);
mu_run_test (test_st64_mul_overflow);
mu_run_test (test_ut8_div_overflow);
mu_run_test (test_st8_div_overflow);
mu_run_test (test_ut16_div_overflow);
mu_run_test (test_st16_div_overflow);
mu_run_test (test_ut32_div_overflow);
mu_run_test (test_st32_div_overflow);
mu_run_test (test_ut64_div_overflow);
mu_run_test (test_st64_div_overflow);
mu_run_test (test_size_t_add_overflow);
mu_run_test (test_size_t_sub_overflow);
mu_run_test (test_size_t_mul_overflow);
mu_run_test (test_boundary_signed_unsigned);
mu_run_test (test_negative_boundary);
#if R_HAVE_BUILTIN_OVERFLOW || (!defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
mu_run_test (test_generic_overflow);
#endif
return tests_passed != tests_run;
}