[PATCH v4 3/4] tests: Clean up double comparisons to avoid compiler warning

Akihiko Odaki posted 4 patches 1 month, 1 week ago
Maintainers: Viktor Prutyanov <viktor.prutyanov@phystech.edu>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Alex Williamson <alex@shazbot.org>, "Cédric Le Goater" <clg@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Markus Armbruster <armbru@redhat.com>, Michael Roth <michael.roth@amd.com>
[PATCH v4 3/4] tests: Clean up double comparisons to avoid compiler warning
Posted by Akihiko Odaki 1 month, 1 week ago
To enable -Wformat-overflow=2, we need to clean up a couple of false
positives:

[2/5] Compiling C object tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o
FAILED: tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o
cc -Itests/unit/test-qobject-output-visitor.p -Itests/unit -I../tests/unit -I. -Iqapi -Itrace -Iui -Iui/shader -Itests -Itests/include -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-6 -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -fsanitize=address -fstack-protector-strong -fsanitize=undefined -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-overflow=2 -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -isystem /home/me/q/var/qemu/linux-headers -isyst!
 em linux-headers -iquote . -iquote /home/me/q/var/qemu -iquote /home/me/q/var/qemu/include -iquote /home/me/q/var/qemu/host/include/aarch64 -iquote /home/me/q/var/qemu/host/include/generic -iquote /home/me/q/var/qemu/tcg/aarch64 -pthread -fPIE -MD -MQ tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o -MF tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o.d -o tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o -c ../tests/unit/test-qobject-output-visitor.c
../tests/unit/test-qobject-output-visitor.c: In function ‘test_visitor_out_list_struct’:
../tests/unit/test-qobject-output-visitor.c:577:28: error: ‘%.6f’ directive writing between 3 and 317 bytes into a region of size 32 [-Werror=format-overflow=]
  577 |         sprintf(expected, "%.6f", (double)i / 3);
      |                            ^~~~
../tests/unit/test-qobject-output-visitor.c:577:27: note: assuming directive output of 8 bytes
  577 |         sprintf(expected, "%.6f", (double)i / 3);
      |                           ^~~~~~
In file included from /usr/include/stdio.h:970,
                 from /home/me/q/var/qemu/include/qemu/osdep.h:114,
                 from ../tests/unit/test-qobject-output-visitor.c:13:
In function ‘sprintf’,
    inlined from ‘test_visitor_out_list_struct’ at ../tests/unit/test-qobject-output-visitor.c:577:9:
/usr/include/bits/stdio2.h:30:10: note: ‘__builtin___sprintf_chk’ output between 4 and 318 bytes into a destination of size 32
   30 |   return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   31 |                                   __glibc_objsize (__s), __fmt,
      |                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   32 |                                   __va_arg_pack ());
      |                                   ~~~~~~~~~~~~~~~~~
../tests/unit/test-qobject-output-visitor.c: In function ‘test_visitor_out_list_struct’:
../tests/unit/test-qobject-output-visitor.c:578:26: error: ‘%.6f’ directive writing between 3 and 317 bytes into a region of size 32 [-Werror=format-overflow=]
  578 |         sprintf(actual, "%.6f", qnum_get_double(qvalue));
      |                          ^~~~
../tests/unit/test-qobject-output-visitor.c:578:25: note: assuming directive output of 8 bytes
  578 |         sprintf(actual, "%.6f", qnum_get_double(qvalue));
      |                         ^~~~~~
In function ‘sprintf’,
    inlined from ‘test_visitor_out_list_struct’ at ../tests/unit/test-qobject-output-visitor.c:578:9:
/usr/include/bits/stdio2.h:30:10: note: ‘__builtin___sprintf_chk’ output between 4 and 318 bytes into a destination of size 32
   30 |   return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   31 |                                   __glibc_objsize (__s), __fmt,
      |                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   32 |                                   __va_arg_pack ());
      |                                   ~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

These buffers cannot actually overflow because the doubles are
between 0 and 31.0/3 inclusive.

However, formatting doubles just to compare them is silly.  Compare
them directly instead.  To avoid potential rounding trouble, change
the numbers tested to be representable exactly in double.

Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
 tests/unit/test-qobject-input-visitor.c  | 8 ++------
 tests/unit/test-qobject-output-visitor.c | 7 ++-----
 2 files changed, 4 insertions(+), 11 deletions(-)

diff --git a/tests/unit/test-qobject-input-visitor.c b/tests/unit/test-qobject-input-visitor.c
index 84bdcdf702e0..beee11db4e47 100644
--- a/tests/unit/test-qobject-input-visitor.c
+++ b/tests/unit/test-qobject-input-visitor.c
@@ -500,7 +500,7 @@ static void test_visitor_in_list_struct(TestInputVisitorData *data,
     g_string_append_printf(json, "'number': [");
     sep = "";
     for (i = 0; i < 32; i++) {
-        g_string_append_printf(json, "%s%f", sep, (double)i / 3);
+        g_string_append_printf(json, "%s%f", sep, (double)i / FLT_RADIX);
         sep = ", ";
     }
     g_string_append_printf(json, "], ");
@@ -583,11 +583,7 @@ static void test_visitor_in_list_struct(TestInputVisitorData *data,
 
     i = 0;
     for (num_list = arrs->number; num_list; num_list = num_list->next) {
-        char expected[32], actual[32];
-
-        sprintf(expected, "%.6f", (double)i / 3);
-        sprintf(actual, "%.6f", num_list->value);
-        g_assert_cmpstr(expected, ==, actual);
+        g_assert_cmpfloat(num_list->value, ==, (double)i / FLT_RADIX);
         i++;
     }
 
diff --git a/tests/unit/test-qobject-output-visitor.c b/tests/unit/test-qobject-output-visitor.c
index 407ab9ed505a..3c47b28f6638 100644
--- a/tests/unit/test-qobject-output-visitor.c
+++ b/tests/unit/test-qobject-output-visitor.c
@@ -538,7 +538,7 @@ static void test_visitor_out_list_struct(TestOutputVisitorData *data,
     }
 
     for (i = 31; i >= 0; i--) {
-        QAPI_LIST_PREPEND(arrs->number, (double)i / 3);
+        QAPI_LIST_PREPEND(arrs->number, (double)i / FLT_RADIX);
     }
 
     for (i = 31; i >= 0; i--) {
@@ -571,12 +571,9 @@ static void test_visitor_out_list_struct(TestOutputVisitorData *data,
     i = 0;
     QLIST_FOREACH_ENTRY(qlist, e) {
         QNum *qvalue = qobject_to(QNum, qlist_entry_obj(e));
-        char expected[32], actual[32];
 
         g_assert(qvalue);
-        sprintf(expected, "%.6f", (double)i / 3);
-        sprintf(actual, "%.6f", qnum_get_double(qvalue));
-        g_assert_cmpstr(actual, ==, expected);
+        g_assert_cmpfloat(qnum_get_double(qvalue), ==, (double)i / FLT_RADIX);
         i++;
     }
 

-- 
2.53.0


Re: [PATCH v4 3/4] tests: Clean up double comparisons to avoid compiler warning
Posted by Markus Armbruster 1 month, 1 week ago
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:

> To enable -Wformat-overflow=2, we need to clean up a couple of false
> positives:
>
> [2/5] Compiling C object tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o
> FAILED: tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o
> cc -Itests/unit/test-qobject-output-visitor.p -Itests/unit -I../tests/unit -I. -Iqapi -Itrace -Iui -Iui/shader -Itests -Itests/include -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-6 -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -fsanitize=address -fstack-protector-strong -fsanitize=undefined -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-overflow=2 -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -isystem /home/me/q/var/qemu/linux-headers -isystem linux-headers -iquote . -iquote /home/me/q/var/qemu -iquote /home/me/q/var/qemu/include -iquote /home/me/q/var/qemu/host/include/aarch64 -iquote /home/me/q/var/qemu/host/include/generic -iquote /home/me/q/var/qemu/tcg/aarch64 -pthread -fPIE -MD -MQ tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o -MF tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o.d -o tests/unit/test-qobject-output-visitor.p/test-qobject-output-visitor.c.o -c ../tests/unit/test-qobject-output-visitor.c

I'd omit the three lines above for brevity's sake.

> ../tests/unit/test-qobject-output-visitor.c: In function ‘test_visitor_out_list_struct’:
> ../tests/unit/test-qobject-output-visitor.c:577:28: error: ‘%.6f’ directive writing between 3 and 317 bytes into a region of size 32 [-Werror=format-overflow=]

I'd also omit the remainder of the report.

>   577 |         sprintf(expected, "%.6f", (double)i / 3);
>       |                            ^~~~
> ../tests/unit/test-qobject-output-visitor.c:577:27: note: assuming directive output of 8 bytes
>   577 |         sprintf(expected, "%.6f", (double)i / 3);
>       |                           ^~~~~~
> In file included from /usr/include/stdio.h:970,
>                  from /home/me/q/var/qemu/include/qemu/osdep.h:114,
>                  from ../tests/unit/test-qobject-output-visitor.c:13:
> In function ‘sprintf’,
>     inlined from ‘test_visitor_out_list_struct’ at ../tests/unit/test-qobject-output-visitor.c:577:9:
> /usr/include/bits/stdio2.h:30:10: note: ‘__builtin___sprintf_chk’ output between 4 and 318 bytes into a destination of size 32
>    30 |   return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
>       |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    31 |                                   __glibc_objsize (__s), __fmt,
>       |                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    32 |                                   __va_arg_pack ());
>       |                                   ~~~~~~~~~~~~~~~~~
> ../tests/unit/test-qobject-output-visitor.c: In function ‘test_visitor_out_list_struct’:
> ../tests/unit/test-qobject-output-visitor.c:578:26: error: ‘%.6f’ directive writing between 3 and 317 bytes into a region of size 32 [-Werror=format-overflow=]

I'd similarly abridge this second warning.

>   578 |         sprintf(actual, "%.6f", qnum_get_double(qvalue));
>       |                          ^~~~
> ../tests/unit/test-qobject-output-visitor.c:578:25: note: assuming directive output of 8 bytes
>   578 |         sprintf(actual, "%.6f", qnum_get_double(qvalue));
>       |                         ^~~~~~
> In function ‘sprintf’,
>     inlined from ‘test_visitor_out_list_struct’ at ../tests/unit/test-qobject-output-visitor.c:578:9:
> /usr/include/bits/stdio2.h:30:10: note: ‘__builtin___sprintf_chk’ output between 4 and 318 bytes into a destination of size 32
>    30 |   return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
>       |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    31 |                                   __glibc_objsize (__s), __fmt,
>       |                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    32 |                                   __va_arg_pack ());
>       |                                   ~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
>
> These buffers cannot actually overflow because the doubles are
> between 0 and 31.0/3 inclusive.
>
> However, formatting doubles just to compare them is silly.  Compare
> them directly instead.  To avoid potential rounding trouble, change
> the numbers tested to be representable exactly in double.
>
> Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
> Reviewed-by: Markus Armbruster <armbru@redhat.com>

Thanks!