Created attachment 732337 [details, diff] fix building on clang This one's certainly unordinary: trying to build libnftnl-1.2.0 with clang-12 and -D_FORTIFY_SOURCE=2 fails with the following: > expr.c:285:19: error: no member named '__builtin___snprintf_chk' in 'struct expr_ops' > ret = expr->ops->snprintf(buf + offset, remain, flags, expr); whereas it succeeds with gcc. On closer investigation, clang-cpp does indeed replace the snprintf in the struct, whereas gcc-cpp does not - I have no idea which one is in the wrong here though Steps to reproduce: ebuild $(equery which libnftnl) clean configure (encountered this with 1.2.0, probably happens with other versions too) cd into work/libnftnl-1.2.0 look at the output of clang-cpp -D_FORTIFY_SOURCE=2 -Iinclude -I. -O1 src/expr.c | grep __builtin___snprintf_chk vs cpp -D_FORTIFY_SOURCE=2 -Iinclude -I. -O1 src/expr.c | grep __builtin___snprintf_chk attached is a patch that pushes / pops the snprintf definition for the offending lines of code, this fixes building with clang.
Probably a good enough reproducer to illustrate the divergence: $ cat expr.c #include <stdio.h> struct expr_ops { int (*snprintf)(char *buf, size_t len, const char * fmt, ...); }; void f(const struct expr_ops *ops) { ops->snprintf(NULL, 0, 0, NULL); } $ gcc -D_FORTIFY_SOURCE=2 -O2 -c expr.c -o expr.o; echo "gcc: $?"; clang -D_FORTIFY_SOURCE=2 -O2 -c expr.c -o expr.o; echo "clang: $?" gcc: 0 expr.c:10:8: error: no member named '__builtin___snprintf_chk' in 'struct expr_ops' ops->snprintf(NULL, 0, 0, NULL); ~~~ ^ /usr/include/bits/stdio2.h:77:3: note: expanded from macro 'snprintf' __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, \ ^ 1 error generated. clang: 1 gcc probably treats snprintf as a special identifier: gcc/builtins.def:DEF_C99_BUILTIN (BUILT_IN_SNPRINTF, "snprintf", BT_FN_INT_STRING_SIZE_CONST_STRING_VAR, ATTR_FORMAT_PRINTF_NOTHROW_3_4)
The root cause is glibc's /usr/include/bits/stdio2.h header file. If __va_arg_pack is not defined and __cplusplus is not defined, glibc defines sprintf as the macro: # define sprintf(str, ...) __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __glibc_objsize (str), __VA_ARGS__) and it's this macro definition that triggers the bug in clang. By adding the following two lines to Sergei Trofimovich's example the error can be triggered with both gcc and clang: #include<features.h> #undef __va_arg_pack $ cat expr.c #include<features.h> #undef __va_arg_pack #include <stdio.h> struct expr_ops { int (*snprintf)(char *buf, size_t len, const char * fmt, ...); }; void f(const struct expr_ops *ops) { ops->snprintf(NULL, 0, 0, NULL); } $ gcc -D_FORTIFY_SOURCE=2 -O2 -c expr.c -o expr.o; echo "gcc: $?"; clang -D_FORTIFY_SOURCE=2 -O2 -c expr.c -o expr.o; echo "clang: $?" expr.c: In function ‘f’: expr.c:12:6: error: ‘const struct expr_ops’ has no member named ‘__builtin___snprintf_chk’ 12 | ops->snprintf(NULL, 0, 0, NULL); | ^~ gcc: 1 expr.c:12:8: error: no member named '__builtin___snprintf_chk' in 'struct expr_ops' ops->snprintf(NULL, 0, 0, NULL); ~~~ ^ /usr/include/bits/stdio2.h:77:3: note: expanded from macro 'snprintf' __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, \ ^ 1 error generated. clang: 1
Created attachment 757132 [details, diff] alternate_clang.patch This is an alternate patch to fix clang building errors. Overall, it is a larger patch than the one previously submitted, but fixes the issue without relying on compiler-specific Pragmas.
Indeed, openembedded has the same sort of patch as username234: https://cgit.openembedded.org/meta-openembedded/tree/meta-networking/recipes-filter/libnftnl/libnftnl/0001-avoid-naming-local-function-as-one-of-printf-family.patch?id=a7313d45035ea3340c520a98436de7fa4c8cd49a.
Sent to upstream mailing list. Subject line is `build: fix clang+glibc snprintf substitution error`
(In reply to nvinson234 from comment #5) > Sent to upstream mailing list. Subject line is `build: fix clang+glibc > snprintf substitution error` https://marc.info/?l=netfilter-devel&m=165529290515437&w=2
Fixed upstream commit 84d12cfacf8ddd857a09435f3d982ab6250d250c (HEAD -> master, origin/master, origin/HEAD) Author: Nicholas Vinson <nvinson234@gmail.com> Date: Wed Jun 15 07:35:28 2022 -0400 build: fix clang+glibc snprintf substitution error When building with clang and glibc and -D_FORTIFY_SOURCE=2 is passed to clang, the snprintf member of the expr_ops and obj_ops structures will be incorrectly replaced with __builtin_snprintf_chk() which results in "error: no member named '__builtin___snprintf_chk'" errors at build time. This patch changes the member name from 'snprintf' to 'output' to prevent the replacement. This bug can be emulated using GCC by undefining the __va_arg_pack macro before stdio.h is included. This patch is based on the notes provided in https://bugs.gentoo.org/807766. Signed-off-by: Nicholas Vinson <nvinson234@gmail.com> Signed-off-by: Florian Westphal <fw@strlen.de>
The bug has been closed via the following commit(s): https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=6d5b60ff3245104e71b1cc8c055105454824bf13 commit 6d5b60ff3245104e71b1cc8c055105454824bf13 Author: Sam James <sam@gentoo.org> AuthorDate: 2022-06-15 13:11:45 +0000 Commit: Sam James <sam@gentoo.org> CommitDate: 2022-06-15 13:11:51 +0000 net-libs/libnftnl: fix build w/ Clang and FORTIFY_SOURCE=2 Thanks-to: Nicholas Vinson <nvinson234@gmail.com> Closes: https://bugs.gentoo.org/807766 Signed-off-by: Sam James <sam@gentoo.org> net-libs/libnftnl/Manifest | 1 + net-libs/libnftnl/libnftnl-1.2.2-r1.ebuild | 87 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+)