lint: detect more cases of integer overflow in constant expressions

For unsigned integers, detect when 'a + b' wraps around.
This commit is contained in:
rillig 2024-03-10 14:32:30 +00:00
parent ee9f134f18
commit 51858eeb3e
3 changed files with 32 additions and 36 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: expr_fold.c,v 1.13 2024/03/10 10:31:29 rillig Exp $ */
/* $NetBSD: expr_fold.c,v 1.14 2024/03/10 14:32:30 rillig Exp $ */
# 3 "expr_fold.c"
/*
@ -59,8 +59,7 @@ fold_uminus(void)
/* The '-' is an operator, it is not part of the integer constant. */
take_int(-2147483648);
/* expect+2: warning: operator '+' produces integer overflow [141] */
/* expect+1: warning: operator '-' produces integer overflow [141] */
/* expect+1: warning: operator '+' produces integer overflow [141] */
take_int(-(2147483647 + 1));
/* expect+1: warning: operator '-' produces integer overflow [141] */
take_int(-(-2147483647 - 1));

View File

@ -1,4 +1,4 @@
/* $NetBSD: msg_141.c,v 1.13 2024/03/10 10:31:29 rillig Exp $ */
/* $NetBSD: msg_141.c,v 1.14 2024/03/10 14:32:30 rillig Exp $ */
# 3 "msg_141.c"
// Test for message: operator '%s' produces integer overflow [141]
@ -347,11 +347,11 @@ plus_u64(void)
u64 = 0xffffffffffffffffULL + 0x0000000000000000ULL;
u64 = 0x0000000000000000ULL + 0xffffffffffffffffULL;
u64 = 0xfffffffffffffffeULL + 0x0000000000000001ULL;
/* TODO: expect+1: warning: operator '+' produces integer overflow [141] */
/* expect+1: warning: operator '+' produces integer overflow [141] */
u64 = 0xffffffffffffffffULL + 0x0000000000000001ULL;
/* TODO: expect+1: warning: operator '+' produces integer overflow [141] */
/* expect+1: warning: operator '+' produces integer overflow [141] */
u64 = 0x0000000000000001ULL + 0xffffffffffffffffULL;
/* TODO: expect+1: warning: operator '+' produces integer overflow [141] */
/* expect+1: warning: operator '+' produces integer overflow [141] */
u64 = 0xffffffffffffffffULL + 0xffffffffffffffffULL;
}
@ -374,12 +374,12 @@ void
minus_u32(void)
{
u32 = 0x00000000U - 0x00000000U;
/* TODO: expect+1: warning: operator '-' produces integer overflow [141] */
/* expect+1: warning: operator '-' produces integer overflow [141] */
u32 = 0x00000000U - 0x00000001U;
/* expect+1: warning: operator '-' produces integer overflow [141] */
u32 = 0x00000000U - 0x80000000U;
u32 = 0x80000000U - 0x00000001U;
/* TODO: expect+1: warning: operator '-' produces integer overflow [141] */
/* expect+1: warning: operator '-' produces integer overflow [141] */
u32 = 0x00000000U - 0xffffffffU;
u32 = 0xffffffffU - 0x00000000U;
u32 = 0xffffffffU - 0xffffffffU;

View File

@ -1,4 +1,4 @@
/* $NetBSD: tree.c,v 1.618 2024/03/10 12:50:45 rillig Exp $ */
/* $NetBSD: tree.c,v 1.619 2024/03/10 14:32:30 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: tree.c,v 1.618 2024/03/10 12:50:45 rillig Exp $");
__RCSID("$NetBSD: tree.c,v 1.619 2024/03/10 14:32:30 rillig Exp $");
#endif
#include <float.h>
@ -819,18 +819,12 @@ fold_unsigned_integer(op_t op, uint64_t l, uint64_t r,
return 0;
} else
return l % r;
case PLUS:;
uint64_t plus_result = l + r;
uint64_t hi = max_value ^ (max_value >> 1);
if (l & hi && r & hi && !(plus_result & hi))
*overflow = true;
return plus_result;
case MINUS:;
uint64_t minus_result = l - r;
hi = max_value ^ (max_value >> 1);
if (!(l & hi) && r & hi && minus_result & hi)
*overflow = true;
return minus_result;
case PLUS:
*overflow = l > max_value - r;
return l + r;
case MINUS:
*overflow = l < r;
return l - r;
case SHL:
/* TODO: warn about out-of-bounds 'sr'. */
return l << (r & 63);
@ -910,23 +904,26 @@ fold_signed_integer(op_t op, int64_t l, int64_t r,
return 0;
}
return l % r;
case PLUS:;
uint64_t plus_result = (uint64_t)l + (uint64_t)r;
hi = (uint64_t)max_value + 1;
if (l & hi && r & hi && !(plus_result & hi))
case PLUS:
if (r > 0 && l > max_value - r) {
*overflow = true;
if (!(l & hi) && !(r & hi) && plus_result & hi)
return max_value;
}
if (r < 0 && l < min_value - r) {
*overflow = true;
return (int64_t)plus_result;
case MINUS:;
uint64_t minus_result = (uint64_t)l - (uint64_t)r;
hi = (uint64_t)max_value + 1;
if (l & hi && !(r & hi) && !(minus_result & hi))
return min_value;
}
return l + r;
case MINUS:
if (r > 0 && l < min_value + r) {
*overflow = true;
if (!(l & hi) && r & hi && minus_result & hi)
return min_value;
}
if (r < 0 && l > max_value + r) {
*overflow = true;
return (int64_t)minus_result;
return max_value;
}
return l - r;
case SHL:
/* TODO: warn about out-of-bounds 'sr'. */
/* TODO: warn about overflow in signed '<<'. */