[libvirt PATCH 0/4] misc fixes for GCC 10

This fixes problem that exhibit themselves with GCC 10, either the Debian Sid cross-compilers on 32-bit, or with Fedora rawhide mingw. Daniel P. Berrangé (4): util: refactor code to workaround gcc 10.1.0 bug m4: enable -fstack-protector-strong on mingw tests: don't mock the time() function on mingw tools: be more paranoid about possibly NULL description m4/virt-compile-warnings.m4 | 4 +--- src/util/virnetdevip.c | 17 ++++++++--------- tests/virnetdaemonmock.c | 2 ++ tools/vsh.c | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) -- 2.24.1

gcc 10.1.0 on Debian sid has a bug where the bounds checking gets confused beteen two branches: In file included from /usr/include/string.h:495, from ../../src/internal.h:28, from ../../src/util/virsocket.h:21, from ../../src/util/virsocketaddr.h:21, from ../../src/util/virnetdevip.h:21, from ../../src/util/virnetdevip.c:21: In function 'memcpy', inlined from 'virNetDevGetifaddrsAddress' at ../../src/util/virnetdevip.c:914:13, inlined from 'virNetDevIPAddrGet' at ../../src/util/virnetdevip.c:962:16: /usr/include/arm-linux-gnueabihf/bits/string_fortified.h:34:10: error: '__builtin_memcpy' offset [16, 27] from the object at 'addr' is out of the bounds of referenced subobject 'inet4' with type 'struct sockaddr_in' at offset 0 [-Werror=array-bounds] 34 | return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../../src/util/virnetdevip.h:21, from ../../src/util/virnetdevip.c:21: ../../src/util/virnetdevip.c: In function 'virNetDevIPAddrGet': ../../src/util/virsocketaddr.h:29:28: note: subobject 'inet4' declared here 29 | struct sockaddr_in inet4; | ^~~~~ cc1: all warnings being treated as errors Note the source location is pointing to the "inet6" / AF_INET6 branch of the "if", but is complaining about bounds of the "inet4" field. Changing the code into a switch() is sufficient to avoid triggering the bug and is arguably better code too. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/util/virnetdevip.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/util/virnetdevip.c b/src/util/virnetdevip.c index ba9e567e5a..8b85c7beca 100644 --- a/src/util/virnetdevip.c +++ b/src/util/virnetdevip.c @@ -897,26 +897,25 @@ virNetDevGetifaddrsAddress(const char *ifname, } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - int family; - if (STRNEQ_NULLABLE(ifa->ifa_name, ifname)) continue; if (!ifa->ifa_addr) continue; - family = ifa->ifa_addr->sa_family; - - if (family != AF_INET6 && family != AF_INET) - continue; - if (family == AF_INET6) { + switch (ifa->ifa_addr->sa_family) { + case AF_INET6: addr->len = sizeof(addr->data.inet6); memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len); - } else { + break; + case AF_INET: addr->len = sizeof(addr->data.inet4); memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len); + break; + default: + continue; } - addr->data.stor.ss_family = family; + addr->data.stor.ss_family = ifa->ifa_addr->sa_family; ret = 0; goto cleanup; } -- 2.24.1

On 7/22/20 1:21 PM, Daniel P. Berrangé wrote:
gcc 10.1.0 on Debian sid has a bug where the bounds checking gets confused beteen two branches:
In file included from /usr/include/string.h:495, from ../../src/internal.h:28, from ../../src/util/virsocket.h:21, from ../../src/util/virsocketaddr.h:21, from ../../src/util/virnetdevip.h:21, from ../../src/util/virnetdevip.c:21: In function 'memcpy', inlined from 'virNetDevGetifaddrsAddress' at ../../src/util/virnetdevip.c:914:13, inlined from 'virNetDevIPAddrGet' at ../../src/util/virnetdevip.c:962:16: /usr/include/arm-linux-gnueabihf/bits/string_fortified.h:34:10: error: '__builtin_memcpy' offset [16, 27] from the object at 'addr' is out of the bounds of referenced subobject 'inet4' with type 'struct sockaddr_in' at offset 0 [-Werror=array-bounds] 34 | return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../../src/util/virnetdevip.h:21, from ../../src/util/virnetdevip.c:21: ../../src/util/virnetdevip.c: In function 'virNetDevIPAddrGet': ../../src/util/virsocketaddr.h:29:28: note: subobject 'inet4' declared here 29 | struct sockaddr_in inet4; | ^~~~~ cc1: all warnings being treated as errors
Note the source location is pointing to the "inet6" / AF_INET6 branch of the "if", but is complaining about bounds of the "inet4" field. Changing the code into a switch() is sufficient to avoid triggering the bug and is arguably better code too.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(Huh, I thought I sent an ack for this when you posted it the first time this morning, but I guess it failed to send, so it was still sitting in an obscured window on my screen...) I don't have a system running gcc 10 yet, but this code looks to provide identical functionality, and still works with gcc 9.3.1 Reviewed-by: Laine Stump <laine@redhat.com>
--- src/util/virnetdevip.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/src/util/virnetdevip.c b/src/util/virnetdevip.c index ba9e567e5a..8b85c7beca 100644 --- a/src/util/virnetdevip.c +++ b/src/util/virnetdevip.c @@ -897,26 +897,25 @@ virNetDevGetifaddrsAddress(const char *ifname, }
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - int family; - if (STRNEQ_NULLABLE(ifa->ifa_name, ifname)) continue;
if (!ifa->ifa_addr) continue; - family = ifa->ifa_addr->sa_family; - - if (family != AF_INET6 && family != AF_INET) - continue;
- if (family == AF_INET6) { + switch (ifa->ifa_addr->sa_family) { + case AF_INET6: addr->len = sizeof(addr->data.inet6); memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len); - } else { + break; + case AF_INET: addr->len = sizeof(addr->data.inet4); memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len); + break; + default: + continue; } - addr->data.stor.ss_family = family; + addr->data.stor.ss_family = ifa->ifa_addr->sa_family; ret = 0; goto cleanup; }

Historically we avoided -fstack-protector* since it resulted in a broken build on Mingw. In GCC 10 in Fedora though, we have the opposite problem, getting a broken build if we don't enable one of the -fstack-protector* options. This also works in GCC 9, so we don't need to worry about the old brokeness which evidentally got fixed at some time without noticing. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- m4/virt-compile-warnings.m4 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/m4/virt-compile-warnings.m4 b/m4/virt-compile-warnings.m4 index d3538d59f8..d171d09991 100644 --- a/m4/virt-compile-warnings.m4 +++ b/m4/virt-compile-warnings.m4 @@ -169,13 +169,11 @@ AC_DEFUN([LIBVIRT_COMPILE_WARNINGS],[ gl_WARN_ADD([-Wframe-larger-than=262144], [RELAXED_FRAME_LIMIT_CFLAGS]) # Extra special flags - dnl -fstack-protector stuff passes gl_WARN_ADD with gcc - dnl on Mingw32, but fails when actually used case $host in aarch64-*-*) dnl "error: -fstack-protector not supported for this target [-Werror]" ;; - *-*-linux*) + *-*-linux* | *-*-mingw*) dnl Prefer -fstack-protector-strong if it's available. dnl There doesn't seem to be great overhead in adding dnl -fstack-protector-all instead of -fstack-protector. -- 2.24.1

On 7/22/20 1:21 PM, Daniel P. Berrangé wrote:
Historically we avoided -fstack-protector* since it resulted in a broken build on Mingw. In GCC 10 in Fedora though, we have the opposite problem, getting a broken build if we don't enable one of the -fstack-protector* options. This also works in GCC 9, so we don't need to worry about the old brokeness which evidentally got fixed at some time without noticing.
...and I guess there's no "super old" mingw releases that we need to worry about, since it's always the mingw on the current release of Fedora that's used (did I get that right?) Reviewed-by: Laine Stump <laine@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- m4/virt-compile-warnings.m4 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/m4/virt-compile-warnings.m4 b/m4/virt-compile-warnings.m4 index d3538d59f8..d171d09991 100644 --- a/m4/virt-compile-warnings.m4 +++ b/m4/virt-compile-warnings.m4 @@ -169,13 +169,11 @@ AC_DEFUN([LIBVIRT_COMPILE_WARNINGS],[ gl_WARN_ADD([-Wframe-larger-than=262144], [RELAXED_FRAME_LIMIT_CFLAGS])
# Extra special flags - dnl -fstack-protector stuff passes gl_WARN_ADD with gcc - dnl on Mingw32, but fails when actually used case $host in aarch64-*-*) dnl "error: -fstack-protector not supported for this target [-Werror]" ;; - *-*-linux*) + *-*-linux* | *-*-mingw*) dnl Prefer -fstack-protector-strong if it's available. dnl There doesn't seem to be great overhead in adding dnl -fstack-protector-all instead of -fstack-protector.

On Wed, Jul 22, 2020 at 01:51:15PM -0400, Laine Stump wrote:
On 7/22/20 1:21 PM, Daniel P. Berrangé wrote:
Historically we avoided -fstack-protector* since it resulted in a broken build on Mingw. In GCC 10 in Fedora though, we have the opposite problem, getting a broken build if we don't enable one of the -fstack-protector* options. This also works in GCC 9, so we don't need to worry about the old brokeness which evidentally got fixed at some time without noticing.
...and I guess there's no "super old" mingw releases that we need to worry about, since it's always the mingw on the current release of Fedora that's used (did I get that right?)
Yeah, we only try to build with currently shipping versions in Fedora. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

The mingw header define time() as a static inline function and this causes a duplicate definition build failure. Since we're not using the LD_PRELOAD at all on Mingw, we ideally wouldn't compile any of the mock libraries. Rather than change the build system now though, this just stubs out the offending function. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- tests/virnetdaemonmock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/virnetdaemonmock.c b/tests/virnetdaemonmock.c index 3b92fff8c9..c523da0791 100644 --- a/tests/virnetdaemonmock.c +++ b/tests/virnetdaemonmock.c @@ -23,6 +23,7 @@ #define VIR_FROM_THIS VIR_FROM_NONE +#ifndef WIN32 time_t time(time_t *t) { const time_t ret = 1234567890; @@ -30,3 +31,4 @@ time_t time(time_t *t) *t = ret; return ret; } +#endif -- 2.24.1

On 7/22/20 1:21 PM, Daniel P. Berrangé wrote:
The mingw header define time() as a static inline function and this causes a duplicate definition build failure. Since we're not using the LD_PRELOAD at all on Mingw, we ideally wouldn't compile any of the mock libraries. Rather than change the build system now though, this just stubs out the offending function.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
--- tests/virnetdaemonmock.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/tests/virnetdaemonmock.c b/tests/virnetdaemonmock.c index 3b92fff8c9..c523da0791 100644 --- a/tests/virnetdaemonmock.c +++ b/tests/virnetdaemonmock.c @@ -23,6 +23,7 @@
#define VIR_FROM_THIS VIR_FROM_NONE
+#ifndef WIN32 time_t time(time_t *t) { const time_t ret = 1234567890; @@ -30,3 +31,4 @@ time_t time(time_t *t) *t = ret; return ret; } +#endif

On 7/22/20 7:21 PM, Daniel P. Berrangé wrote:
The mingw header define time() as a static inline function and this causes a duplicate definition build failure. Since we're not using the LD_PRELOAD at all on Mingw, we ideally wouldn't compile any of the mock libraries. Rather than change the build system now though, this just stubs out the offending function.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- tests/virnetdaemonmock.c | 2 ++ 1 file changed, 2 insertions(+)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal

GCC 10 complains about "desc" possibly being a NULL dereference. Even though it is a false positive, we can easily avoid it. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- tools/vsh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/vsh.c b/tools/vsh.c index 527c135424..b65e99cbd2 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -689,7 +689,7 @@ vshCmddefHelp(vshControl *ctl, const vshCmdDef *def) fputc('\n', stdout); desc = vshCmddefGetInfo(def, "desc"); - if (*desc) { + if (desc && *desc) { /* Print the description only if it's not empty. */ fputs(_("\n DESCRIPTION\n"), stdout); fprintf(stdout, " %s\n", _(desc)); -- 2.24.1

On 7/22/20 1:21 PM, Daniel P. Berrangé wrote:
GCC 10 complains about "desc" possibly being a NULL dereference. Even though it is a false positive, we can easily avoid it.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com> So those were the only complaints of gcc 10? We got off easy :-)
--- tools/vsh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/vsh.c b/tools/vsh.c index 527c135424..b65e99cbd2 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -689,7 +689,7 @@ vshCmddefHelp(vshControl *ctl, const vshCmdDef *def) fputc('\n', stdout);
desc = vshCmddefGetInfo(def, "desc"); - if (*desc) { + if (desc && *desc) { /* Print the description only if it's not empty. */ fputs(_("\n DESCRIPTION\n"), stdout); fprintf(stdout, " %s\n", _(desc));

On 7/22/20 7:21 PM, Daniel P. Berrangé wrote:
GCC 10 complains about "desc" possibly being a NULL dereference. Even though it is a false positive, we can easily avoid it.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- tools/vsh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
participants (3)
-
Daniel P. Berrangé
-
Laine Stump
-
Michal Privoznik