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) {