Bug 25399

Summary: undefined reference to `__warn_memset_zero_len' when changing gnuc version
Product: glibc Reporter: sguelton
Component: stringAssignee: Not yet assigned to anyone <unassigned>
Severity: normal CC: fweimer, jakub, ovilewade9, siddhesh
Priority: P2 Flags: fweimer: security-
Version: unspecified   
Target Milestone: 2.33   
Host: Target:
Build: Last reconfirmed:

Description sguelton 2020-01-16 10:41:37 UTC
When compiling the following program

#undef __GNUC__
#define __GNUC__ 4
#undef __GNUC_MINOR__
#define __GNUC_MINOR__ 9

#include <string.h>
char a[64];
int main ()
  memset (a, 64, 0);
  return 0;

with a decent gcc version (8.3) and glibc version (2.28), I get a link error

gcc a.c -D_FORTIFY_SOURCE=2 -O2
In file included from /usr/include/string.h:494,
                 from a.c:6:
In function ‘memset’,
    inlined from ‘main’ at a.c:10:3:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:67:7: warning: call to ‘__warn_memset_zero_len’ declared with attribute warning: memset used with constant zero length parameter; this could be due to transposed parameters
       __warn_memset_zero_len ();
/usr/bin/ld: /tmp/cc7RDLx1.o: in function `main':
a.c:(.text.startup+0x5): undefined reference to `__warn_memset_zero_len'
collect2: error: ld returned 1 exit status

No link error if I don't force the __GNUC__ and __GNUC_MINOR__.

I've checked the source of glibc-2.30, and the problem seems related to

#if !__GNUC_PREREQ (5,0)
__warndecl (__warn_memset_zero_len,
      "memset used with constant zero length parameter; this could be due to transposed parameters");

while `__warn_memset_zero_len` is not defined elsewhere.

In addition to binding glibc to some gcc version, it is also a problem for non-gcc compilers, like clang, which set GNU C version to 3.2 by default (see for instance https://reviews.llvm.org/D71082#1822925)
Comment 1 Jakub Jelinek 2020-01-16 17:24:44 UTC
debug/warning-nop.c should provide those symbols in libc.a (and libc_nonshared.a ?), but for some reason it doesn't work anymore.
Comment 2 Andreas Schwab 2020-01-16 18:21:40 UTC
When glibc is compiled with GCC >= 5 the __warndecl in <bits/string3.h> is compiled out, so debug/warning-nop.c gets empty.
Comment 3 Jakub Jelinek 2020-01-16 18:27:27 UTC
Indeed, that's it.
So perhaps we need:
/* Pretend compilation with GCC 4.9 if compiled by GCC >= 5, so that __warndecl are not skipped.  */
#if __GNUC_PREREQ (5, 0)
#undef __GNUC__
#define __GNUC__ 4
#undef __GNUC_MINOR__
#define __GNUC_MINOR__ 9
(or instead of __GNUC_PREREQ the longer check and do this before including the first header in warning-nop.c).
Comment 4 Siddhesh Poyarekar 2020-11-05 04:44:35 UTC
This compilation issue has been fixed[1] upstream; clang and other non-gcc compilers should now be able to build the reproducer correctly without any linker errors.

There is the outstanding issue where static libraries and objects built with older compilers against the older glibc may refuse to link correctly with current glibc.  The __warn_memset_zero_len symbol has been missing for a while now and nobody has complained specifically about that yet, so it appears that this issue is rare and if not, being worked around in other ways.

If one needs this to be fixed in glibc by providing __warn_memset_zero_len and provide the linker warning, please file a new bug report to discuss it.

[1] https://sourceware.org/pipermail/glibc-cvs/2020q4/070949.html
Comment 5 Florian Weimer 2020-11-05 16:12:46 UTC
Fixed by:

commit dc274b141666766b8ef70992d887e3c0c5e41bed
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Tue Nov 3 15:09:28 2020 +0530

    Remove __warn_memset_zero_len [BZ #25399]
    Non-gcc compilers (clang and possibly other compilers that do not
    masquerade as gcc 5.0 or later) are unable to use
    __warn_memset_zero_len since the symbol is no longer available on
    glibc built with gcc 5.0 or later.  While it was likely an oversight
    that caused this omission, the fact that it wasn't noticed until
    recently (when clang closed the gap on _FORTIFY_SUPPORT) that the
    symbol was missing.
    Given that both gcc and clang are capable of doing this check in the
    compiler, drop all remaining signs of __warn_memset_zero_len from
    glibc so that no more objects are built with this symbol in future.

We should consider backports.
Comment 6 ovile009988 2021-08-25 16:36:07 UTC Comment hidden (spam)