Module Name: src
Committed By: rillig
Date: Thu Jan 2 20:02:59 UTC 2025
Modified Files:
src/tests/usr.bin/xlint/lint1: msg_132.c
src/usr.bin/xlint/lint1: tree.c
Log Message:
lint: fix possible loss of accuracy in multiplication and division
To generate a diff of this commit:
cvs rdiff -u -r1.51 -r1.52 src/tests/usr.bin/xlint/lint1/msg_132.c
cvs rdiff -u -r1.668 -r1.669 src/usr.bin/xlint/lint1/tree.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/tests/usr.bin/xlint/lint1/msg_132.c
diff -u src/tests/usr.bin/xlint/lint1/msg_132.c:1.51 src/tests/usr.bin/xlint/lint1/msg_132.c:1.52
--- src/tests/usr.bin/xlint/lint1/msg_132.c:1.51 Thu Jan 2 18:36:52 2025
+++ src/tests/usr.bin/xlint/lint1/msg_132.c Thu Jan 2 20:02:59 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: msg_132.c,v 1.51 2025/01/02 18:36:52 rillig Exp $ */
+/* $NetBSD: msg_132.c,v 1.52 2025/01/02 20:02:59 rillig Exp $ */
# 3 "msg_132.c"
// Test for message: conversion from '%s' to '%s' may lose accuracy [132]
@@ -251,14 +251,28 @@ test_ic_mult(void)
// from __BITS, __SHIFTIN, __SHIFTOUT
u32 = (u16 & 1023ULL) / 1ULL * 1024ULL | (u16 & 1023ULL) / 1ULL * 1ULL;
- // FIXME
- /* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
s8 = 1 * s8;
- // FIXME
- /* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
s16 = 1 * s16;
s32 = 1 * s32;
s64 = 1 * s64;
+
+ /* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
+ s8 = 2 * s8;
+ /* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
+ s16 = 2 * s16;
+ // No warning, as there is no narrowing conversion.
+ s32 = 2 * s32;
+ // No warning, as there is no narrowing conversion.
+ s64 = 2 * s64;
+
+ /* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
+ s8 = -1 * s8;
+ /* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
+ s16 = -1 * s16;
+ // No warning, as there is no narrowing conversion.
+ s32 = -1 * s32;
+ // No warning, as there is no narrowing conversion.
+ s64 = -1 * s64;
}
void
@@ -272,14 +286,19 @@ test_ic_div(void)
/* expect+1: warning: conversion from 'unsigned int' to 'unsigned short' may lose accuracy [132] */
u16 = u32 / 65535;
- // FIXME
- /* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
s8 = s8 / 1;
- // FIXME
- /* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
s16 = s16 / 1;
s32 = s32 / 1;
s64 = s64 / 1;
+
+ /* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
+ s8 = s8 / -1;
+ /* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
+ s16 = s16 / -1;
+ // No warning, as there is no narrowing conversion.
+ s32 = s32 / -1;
+ // No warning, as there is no narrowing conversion.
+ s64 = s64 / -1;
}
void
Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.668 src/usr.bin/xlint/lint1/tree.c:1.669
--- src/usr.bin/xlint/lint1/tree.c:1.668 Thu Jan 2 18:36:51 2025
+++ src/usr.bin/xlint/lint1/tree.c Thu Jan 2 20:02:59 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: tree.c,v 1.668 2025/01/02 18:36:51 rillig Exp $ */
+/* $NetBSD: tree.c,v 1.669 2025/01/02 20:02:59 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.668 2025/01/02 18:36:51 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.669 2025/01/02 20:02:59 rillig Exp $");
#endif
#include <float.h>
@@ -147,6 +147,22 @@ si_min_value(const type_t *tp)
}
static int64_t
+si_mult_sat(const type_t *tp, int64_t l, int64_t r)
+{
+ uint64_t al = s64_abs(l);
+ uint64_t ar = s64_abs(r);
+ bool neg = (l >= 0) != (r >= 0);
+ uint64_t max = ui_max_value(tp);
+ uint64_t max_prod = (uint64_t)max + (neg ? 1 : 0);
+ if (al == 0 || ar <= max_prod / al)
+ return l * r;
+ else if (neg)
+ return -1 - (int64_t)(max >> 1);
+ else
+ return (int64_t)(max >> 1);
+}
+
+static int64_t
si_plus_sat(const type_t *tp, int64_t a, int64_t b)
{
if (b >= 0) {
@@ -211,8 +227,21 @@ ic_mult(const type_t *tp, integer_constr
{
integer_constraints c;
- if (ic_maybe_signed_binary(tp, a, b)
- || (a.umax > 0 && b.umax > ic_any(tp).umax / a.umax))
+ if (ic_maybe_signed_binary(tp, a, b)) {
+ int64_t ll = si_mult_sat(tp, a.smin, b.smin);
+ int64_t lu = si_mult_sat(tp, a.smin, b.smax);
+ int64_t ul = si_mult_sat(tp, a.smax, b.smin);
+ int64_t uu = si_mult_sat(tp, a.smax, b.smax);
+
+ c.smin = s64_min(ll, s64_min(lu, s64_min(ul, uu)));
+ c.smax = s64_max(ll, s64_max(lu, s64_max(ul, uu)));
+ c.umin = c.smin >= 0 ? (uint64_t)c.smin : 0;
+ c.umax = c.smin >= 0 ? (uint64_t)c.smax : UINT64_MAX;
+ c.bclr = ~u64_fill_right(c.umax);
+ return c;
+ }
+
+ if (a.umax > 0 && b.umax > ic_any(tp).umax / a.umax)
return ic_any(tp);
c.smin = INT64_MIN;
@@ -226,8 +255,11 @@ ic_mult(const type_t *tp, integer_constr
static integer_constraints
ic_div(const type_t *tp, integer_constraints a, integer_constraints b)
{
- if (ic_maybe_signed_binary(tp, a, b))
+ if (ic_maybe_signed_binary(tp, a, b)) {
+ if (b.smin >= 0)
+ return a;
return ic_any(tp);
+ }
integer_constraints c;
c.smin = INT64_MIN;
@@ -1102,8 +1134,8 @@ fold_signed_integer(op_t op, int64_t l,
*overflow = l == min_value;
return *overflow ? l : -l;
case MULT:;
- uint64_t al = l >= 0 ? (uint64_t)l : -(uint64_t)l;
- uint64_t ar = r >= 0 ? (uint64_t)r : -(uint64_t)r;
+ uint64_t al = s64_abs(l);
+ uint64_t ar = s64_abs(r);
bool neg = (l >= 0) != (r >= 0);
uint64_t max_prod = (uint64_t)max_value + (neg ? 1 : 0);
if (al > 0 && ar > max_prod / al) {