Skip to content

Commit fbc150b

Browse files
committed
lint: fix possible loss of accuracy in multiplication and division
1 parent 9e0de8e commit fbc150b

2 files changed

Lines changed: 67 additions & 16 deletions

File tree

tests/usr.bin/xlint/lint1/msg_132.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: msg_132.c,v 1.51 2025/01/02 18:36:52 rillig Exp $ */
1+
/* $NetBSD: msg_132.c,v 1.52 2025/01/02 20:02:59 rillig Exp $ */
22
# 3 "msg_132.c"
33

44
// Test for message: conversion from '%s' to '%s' may lose accuracy [132]
@@ -251,14 +251,28 @@ test_ic_mult(void)
251251
// from __BITS, __SHIFTIN, __SHIFTOUT
252252
u32 = (u16 & 1023ULL) / 1ULL * 1024ULL | (u16 & 1023ULL) / 1ULL * 1ULL;
253253

254-
// FIXME
255-
/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
256254
s8 = 1 * s8;
257-
// FIXME
258-
/* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
259255
s16 = 1 * s16;
260256
s32 = 1 * s32;
261257
s64 = 1 * s64;
258+
259+
/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
260+
s8 = 2 * s8;
261+
/* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
262+
s16 = 2 * s16;
263+
// No warning, as there is no narrowing conversion.
264+
s32 = 2 * s32;
265+
// No warning, as there is no narrowing conversion.
266+
s64 = 2 * s64;
267+
268+
/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
269+
s8 = -1 * s8;
270+
/* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
271+
s16 = -1 * s16;
272+
// No warning, as there is no narrowing conversion.
273+
s32 = -1 * s32;
274+
// No warning, as there is no narrowing conversion.
275+
s64 = -1 * s64;
262276
}
263277

264278
void
@@ -272,14 +286,19 @@ test_ic_div(void)
272286
/* expect+1: warning: conversion from 'unsigned int' to 'unsigned short' may lose accuracy [132] */
273287
u16 = u32 / 65535;
274288

275-
// FIXME
276-
/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
277289
s8 = s8 / 1;
278-
// FIXME
279-
/* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
280290
s16 = s16 / 1;
281291
s32 = s32 / 1;
282292
s64 = s64 / 1;
293+
294+
/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
295+
s8 = s8 / -1;
296+
/* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
297+
s16 = s16 / -1;
298+
// No warning, as there is no narrowing conversion.
299+
s32 = s32 / -1;
300+
// No warning, as there is no narrowing conversion.
301+
s64 = s64 / -1;
283302
}
284303

285304
void

usr.bin/xlint/lint1/tree.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: tree.c,v 1.668 2025/01/02 18:36:51 rillig Exp $ */
1+
/* $NetBSD: tree.c,v 1.669 2025/01/02 20:02:59 rillig Exp $ */
22

33
/*
44
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
3737

3838
#include <sys/cdefs.h>
3939
#if defined(__RCSID)
40-
__RCSID("$NetBSD: tree.c,v 1.668 2025/01/02 18:36:51 rillig Exp $");
40+
__RCSID("$NetBSD: tree.c,v 1.669 2025/01/02 20:02:59 rillig Exp $");
4141
#endif
4242

4343
#include <float.h>
@@ -146,6 +146,22 @@ si_min_value(const type_t *tp)
146146
return -si_max_value(tp) - 1;
147147
}
148148

149+
static int64_t
150+
si_mult_sat(const type_t *tp, int64_t l, int64_t r)
151+
{
152+
uint64_t al = s64_abs(l);
153+
uint64_t ar = s64_abs(r);
154+
bool neg = (l >= 0) != (r >= 0);
155+
uint64_t max = ui_max_value(tp);
156+
uint64_t max_prod = (uint64_t)max + (neg ? 1 : 0);
157+
if (al == 0 || ar <= max_prod / al)
158+
return l * r;
159+
else if (neg)
160+
return -1 - (int64_t)(max >> 1);
161+
else
162+
return (int64_t)(max >> 1);
163+
}
164+
149165
static int64_t
150166
si_plus_sat(const type_t *tp, int64_t a, int64_t b)
151167
{
@@ -211,8 +227,21 @@ ic_mult(const type_t *tp, integer_constraints a, integer_constraints b)
211227
{
212228
integer_constraints c;
213229

214-
if (ic_maybe_signed_binary(tp, a, b)
215-
|| (a.umax > 0 && b.umax > ic_any(tp).umax / a.umax))
230+
if (ic_maybe_signed_binary(tp, a, b)) {
231+
int64_t ll = si_mult_sat(tp, a.smin, b.smin);
232+
int64_t lu = si_mult_sat(tp, a.smin, b.smax);
233+
int64_t ul = si_mult_sat(tp, a.smax, b.smin);
234+
int64_t uu = si_mult_sat(tp, a.smax, b.smax);
235+
236+
c.smin = s64_min(ll, s64_min(lu, s64_min(ul, uu)));
237+
c.smax = s64_max(ll, s64_max(lu, s64_max(ul, uu)));
238+
c.umin = c.smin >= 0 ? (uint64_t)c.smin : 0;
239+
c.umax = c.smin >= 0 ? (uint64_t)c.smax : UINT64_MAX;
240+
c.bclr = ~u64_fill_right(c.umax);
241+
return c;
242+
}
243+
244+
if (a.umax > 0 && b.umax > ic_any(tp).umax / a.umax)
216245
return ic_any(tp);
217246

218247
c.smin = INT64_MIN;
@@ -226,8 +255,11 @@ ic_mult(const type_t *tp, integer_constraints a, integer_constraints b)
226255
static integer_constraints
227256
ic_div(const type_t *tp, integer_constraints a, integer_constraints b)
228257
{
229-
if (ic_maybe_signed_binary(tp, a, b))
258+
if (ic_maybe_signed_binary(tp, a, b)) {
259+
if (b.smin >= 0)
260+
return a;
230261
return ic_any(tp);
262+
}
231263

232264
integer_constraints c;
233265
c.smin = INT64_MIN;
@@ -1102,8 +1134,8 @@ fold_signed_integer(op_t op, int64_t l, int64_t r,
11021134
*overflow = l == min_value;
11031135
return *overflow ? l : -l;
11041136
case MULT:;
1105-
uint64_t al = l >= 0 ? (uint64_t)l : -(uint64_t)l;
1106-
uint64_t ar = r >= 0 ? (uint64_t)r : -(uint64_t)r;
1137+
uint64_t al = s64_abs(l);
1138+
uint64_t ar = s64_abs(r);
11071139
bool neg = (l >= 0) != (r >= 0);
11081140
uint64_t max_prod = (uint64_t)max_value + (neg ? 1 : 0);
11091141
if (al > 0 && ar > max_prod / al) {

0 commit comments

Comments
 (0)