https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106319

            Bug ID: 106319
           Summary: False positives from -Wanalyzer-va-arg-type-mismatch
                    on int promotion
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: dmalcolm at gcc dot gnu.org
  Target Milestone: ---

Consider e.g.:

static void __attribute__((noinline))
__analyzer_consume_n_ints (int num, ...)
{
  __builtin_va_list ap;
  __builtin_va_start (ap, num);

  int i, v;
  for (i = 0; i < num; i++)
    v = __builtin_va_arg (ap, int);

  __builtin_va_end (ap);
}

void test_int (int x)
{
  __analyzer_consume_n_ints (1, x);
}

void test_3_ints (int x, int y, int z)
{
  __analyzer_consume_n_ints (3, x, y, z);
}

void test_short (short s)
{
  __analyzer_consume_n_ints (1, s);
}

Currently we emit this false postive:

../../src/gcc/testsuite/gcc.dg/analyzer/stdarg-types-3.c: In function
‘__analyzer_consume_n_ints’:
../../src/gcc/testsuite/gcc.dg/analyzer/stdarg-types-3.c:9:7: warning: ‘va_arg’
expected ‘int’ but received ‘short int’ for variadic argument 1 of ‘ap’
[CWE-686] [-Wanalyzer-va-arg-type-mismatch]
    9 |     v = __builtin_va_arg (ap, int);
      |     ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ‘test_short’: events 1-2
    |
    |   24 | void test_short (short s)
    |      |      ^~~~~~~~~~
    |      |      |
    |      |      (1) entry to ‘test_short’
    |   25 | {
    |   26 |   __analyzer_consume_n_ints (1, s);
    |      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |   |
    |      |   (2) calling ‘__analyzer_consume_n_ints’ from ‘test_short’ with 1
variadic argument
    |
    +--> ‘__analyzer_consume_n_ints’: events 3-6
           |
           |    2 | __analyzer_consume_n_ints (int num, ...)
           |      | ^~~~~~~~~~~~~~~~~~~~~~~~~
           |      | |
           |      | (3) entry to ‘__analyzer_consume_n_ints’
           |......
           |    8 |   for (i = 0; i < num; i++)
           |      |               ~~~~~~~
           |      |                 |
           |      |                 (4) following ‘true’ branch (when ‘i <
num’)...
           |    9 |     v = __builtin_va_arg (ap, int);
           |      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |       |
           |      |       (5) ...to here
           |      |       (6) ‘va_arg’ expected ‘int’ but received ‘short int’
for variadic argument 1 of ‘ap’
           |

Reproducer: https://godbolt.org/z/6xrvErbov

>From https://en.cppreference.com/w/c/language/variadic :
"At the function call, each argument that is a part of the variable argument
list undergoes special implicit conversions known as default argument
promotions."

From
https://en.cppreference.com/w/c/language/conversion#Default_argument_promotions
:
"In a function call expression when the call is made to
  1) a function without a prototype
  2) a variadic function, where the argument expression is one of the trailing
arguments that are matched against the ellipsis parameter
Each argument of integer type undergoes integer promotion (see below), and each
argument of type float is implicitly converted to the type double"


>From https://en.cppreference.com/w/c/language/conversion#Integer_promotions :
"Integer promotion is the implicit conversion of a value of any integer type
with rank less or equal to rank of int or of a bit field of type _Bool, int,
signed int, unsigned int, to the value of type int or unsigned int.
If int can represent the entire range of values of the original type (or the
range of values of the original bit field), the value is converted to type int.
Otherwise the value is converted to unsigned int."

Seen on Linux kernel e.g. in drivers/input/keyboard/lm8323.c, where we falsely
complain in lm8323_write_pwm_one about:
  418 |         lm8323_write(pwm->chip, 4, 

with 4 args: int, int, int, u16; the u16 should be promoted to int.

Reply via email to