From b933a4c6ac5bad79f6ac950fb7c7f586d8b4dfec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= Date: Fri, 6 Oct 2017 17:36:34 +0200 Subject: [PATCH] 1.0.2-8 - Evolution of the previous (rhbz#1478089, rhbz#1487787) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New test included in check phase (as per upsteam) Signed-off-by: Jan Pokorný --- ...al-fix-for-libqb-logging-not-working.patch | 336 ------ ...er-explanation-behaviour-of-QB_LOG_I.patch | 66 ++ ...run-attribute-section-test-through-r.patch | 37 +- ...f-tests-dubbed-functional-cover-link.patch | 964 ++++++++++++++++++ ...n-time-client-side-sanity-check-that.patch | 257 +++++ ...r-libqb-logging-not-working-with-ld..patch | 446 ++++++++ ...-object-symbol-s-leak-expose-run-tim.patch | 152 +++ libqb.spec | 17 +- 8 files changed, 1919 insertions(+), 356 deletions(-) delete mode 100644 0002-WIP-5-Experimental-fix-for-libqb-logging-not-working.patch create mode 100644 01-Med-qblog.h-better-explanation-behaviour-of-QB_LOG_I.patch rename 0001-build-configure-run-attribute-section-test-through-r.patch => 02-build-configure-run-attribute-section-test-through-r.patch (57%) create mode 100644 03-tests-new-sort-of-tests-dubbed-functional-cover-link.patch create mode 100644 04-Med-add-extra-run-time-client-side-sanity-check-that.patch create mode 100644 05-High-bare-fix-for-libqb-logging-not-working-with-ld..patch create mode 100644 06-Low-fix-internal-object-symbol-s-leak-expose-run-tim.patch diff --git a/0002-WIP-5-Experimental-fix-for-libqb-logging-not-working.patch b/0002-WIP-5-Experimental-fix-for-libqb-logging-not-working.patch deleted file mode 100644 index 1a613b6..0000000 --- a/0002-WIP-5-Experimental-fix-for-libqb-logging-not-working.patch +++ /dev/null @@ -1,336 +0,0 @@ -From 10cd5db8821e4d313ae5245b33061e02ba8d3ff5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= -Date: Thu, 3 Aug 2017 17:40:09 +0200 -Subject: [PATCH] WIP 5: Experimental fix for libqb logging not working with - ld.bfd 2.29 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -What's missing: -* cross-testing programs vs. libqb prior/after this fix with ld.bfd 2.29 -* program vs. library sanity attestation for good measure - - code header-included in the program could/shall run-time one-off - self-test the library code actually logs anything via custom callback - log handler - - library could/shall attest in qb_log_init that QB_ATTR_SECTION_START - + STOP symbols belong to other address space than its own (dladdr?) -* related to that, we should really enable attribute((__section__)) for - powerpc platforms, it seems to work well there -- and related to that, - we need to figure out how static and dynamic call sites can live - together -- say what will happen to logging programs compiled with - libqb w/o attribute sections when the underlying libqb is flipped - to the one with them... - -Version 2: -Simplify the compilation against libqb for its users that now no -longer need to worry to use a new flag for compilation with the -affected ld version, as semantically the same is already contained -in libqb.so itself (it's now a linker script instead of a common -symlink to the end versioned so file, which something known as an -implicit linker script: -https://sourceware.org/binutils/docs/ld/Implicit-Linker-Scripts.html). - -Version 3: -Ditto for direct libqb.la users (incl. native examples and tests for -which the original Makefile.am form could have been restored thanks -to this -- not a subject of one-time configure check anymore), -to capture the case someone is using that libtool indirection directly -through a private checkout underneath the actual library user's repo. -The solutions is to slightly abuse libtool's library archive handling -and it's implicit dependency propagation within "dependency_libs" -variable, where we inject a reference to our own artificial library -archive that in turn eventually resolves to the discussed linker script. - -Version 4: -Overcomes some unintended RPATH occurrences in qb-blackbox binary -or possibly libqb.so.*. That's definitely not desired: -https://fedoraproject.org/wiki/Packaging:Guidelines#Beware_of_Rpath - -Version 5: -Overcomes issues when HAVE_GCC_ATTRIBUTE_SECTION is not defined, hence -qblog_script.ld script used to carry unresolved symbolic references as -a consequence: https://bugzilla.redhat.com/show_bug.cgi?id=1487787 -Now the script is not used at all in that case, and if accidentally was, -there is an extra guard conditionalizing the content referring to those -values to only the case they are expected to be defined. -Plus some more, missing in retrospect, conditionalizing is added. - -Deficiencies of version 5 (some carried over, apparently): -- see What's missing above -- possibly needs and overhaul regarding documentation of the arrangement - (now scattered throughout the files) - -Deficiencies that are not solvable as long as we use the linker script -to participate in restoring boundary section symbols being global again: -- /usr/bin/ld: warning: ../lib/qblog_script.ld contains output sections; did you forget -T? - -References: -http://oss.clusterlabs.org/pipermail/developers/2017-July/000503.html -https://bugzilla.redhat.com/show_bug.cgi?id=1477354#c8 - -Signed-off-by: Jan Pokorný ---- - configure.ac | 62 +++++++++++++++++++++++++++++++++++++--------- - lib/Makefile.am | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ - lib/log.c | 7 ++++++ - lib/qblog_script.la.in | 15 +++++++++++ - lib/qblog_script.ld.in | 17 +++++++++++++ - 6 files changed, 156 insertions(+), 12 deletions(-) - create mode 100644 lib/qblog_script.la.in - create mode 100644 lib/qblog_script.ld.in - -diff --git a/configure.ac b/configure.ac -index fd37466..f94af71 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -618,31 +618,68 @@ AC_SUBST(HAVE_SLOW_TESTS) - - # --- callsite sections --- - if test "x${GCC}" = xyes; then -+ LDFLAGS_save="${LDFLAGS}" - AC_MSG_CHECKING([whether GCC supports __attribute__((section()) + ld supports orphan sections]) - if test "x${ac_cv_link_attribute_section}" = x ; then -+ LDFLAGS="${LDFLAGS_save} -shared -fPIC" -+ AC_LINK_IFELSE( -+ [AC_LANG_SOURCE( -+ [[#include -+ extern int __start___verbose[], __stop___verbose[]; -+ int test(void) { -+ static int my_var __attribute__((section("__verbose"))) = 3; -+ if (__start___verbose == __stop___verbose) assert(0); -+ return *((int *) __start___verbose); -+ }]])], -+ [gcc_has_attribute_section=yes; cp "conftest${EXEEXT}" "lib_conftest.so"], -+ [gcc_has_attribute_section=no] -+ ) -+ LDFLAGS="${LDFLAGS_save}" -+ else -+ gcc_has_attribute_section=${ac_cv_link_attribute_section} -+ fi -+ AC_MSG_RESULT($gcc_has_attribute_section) -+ -+ # in the failing case (e.g. with ld from binutils 2.29), it's probable -+ # linking will fail readily (hidden symbol `__stop___verbose' in -+ # conftest is referenced by DSO), but keep the sensible test (in-binary -+ # symbol is expected to be propagated into the library, and draw the -+ # full circle back to binary through standard return value passing -+ # (-rpath passed because LD_LIBRARY_PATH exporting is unwieldy here) -+ if test "x${gcc_has_attribute_section}" = xyes; then -+ AC_MSG_CHECKING([whether linker emits global symbols for orphan sections]) -+ LDFLAGS="${LDFLAGS_save} -L. -l_conftest -Wl,-rpath=$(pwd)" - AC_TRY_RUN( - AC_LANG_PROGRAM( - [[#include -- extern void * __start___verbose, * __stop___verbose;]], -+ extern int __start___verbose[], __stop___verbose[]; -+ int test(void);]], - [[static int my_var __attribute__((section("__verbose"))) = 5; - if (__start___verbose == __stop___verbose) assert(0); -- if (my_var == 5) return 0; -- else return -1; -+ return !(my_var == test() /*5?*/); - ]]), -- [gcc_has_attribute_section=yes], -- [gcc_has_attribute_section=no] -+ [gcc_has_attribute_section_visible=yes], -+ [gcc_has_attribute_section_visible=no] - ) -- else -- gcc_has_attribute_section=${ac_cv_link_attribute_section} -- fi -+ LDFLAGS="${LDFLAGS_save}" -+ AC_MSG_RESULT($gcc_has_attribute_section_visible) -+ rm -f "lib_conftest.so" - -- AC_MSG_RESULT($gcc_has_attribute_section) -- if test $gcc_has_attribute_section = yes; then - AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1, - [Enabling code using __attribute__((section))]) -- PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section" -+ if test "x${gcc_has_attribute_section_visible}" = xyes; then -+ PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section" -+ else -+ AC_DEFINE([QB_NEED_ATTRIBUTE_SECTION_WORKAROUND], 1, -+ [Enabling code using __attribute__((section))]) -+ PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section-workaround" -+ fi - fi - fi -+AM_CONDITIONAL(HAVE_GCC_ATTRIBUTE_SECTION, [test "x${gcc_has_attribute_section}" = xyes]) -+AM_CONDITIONAL(NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND, -+ [test "x${gcc_has_attribute_section}" = xyes \ -+ && test "x${gcc_has_attribute_section_visible}" != xyes]) - - # --- ansi --- - if test "x${enable_ansi}" = xyes && \ -@@ -721,7 +758,8 @@ AC_CONFIG_FILES([Makefile - docs/Makefile - docs/common.dox - docs/html.dox -- docs/man.dox]) -+ docs/man.dox -+ lib/qblog_script.la:lib/qblog_script.la.in]) - - AC_OUTPUT - -diff --git a/lib/Makefile.am b/lib/Makefile.am -index 0bebeb5..85dd434 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -19,6 +19,7 @@ - # along with libqb. If not, see . - - -+CLEANFILES = qblog_script.ld - MAINTAINERCLEANFILES = Makefile.in - - noinst_HEADERS = ipc_int.h util_int.h ringbuffer_int.h loop_int.h \ -@@ -39,9 +40,48 @@ source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c \ - log_syslog.c log_dcs.c log_format.c \ - map.c skiplist.c hashtable.c trie.c - -+# Following two files related to linkage using classic ld from binutils 2.29+ -+# with which we cannot afford to lose public access to section boundary symbols -+# (as the mentioned version started to scope them privately by default, see -+# the comment within the first of the files, ultimately leading to broken -+# logging functionality of libqb) deserve a bit of explanation: -+# * qblog_script.ld -+# - linker script that instructs the output section that those symbols should -+# be visible, i.e. supports the same behaviour regardless of ld version -+# - serves two purposes: -+# . local: libqb itself and its "private" (cf. examples) users need those -+# symbols visible, which is achieved with a help of the other file -+# . system-wide: whenever the non-private library users link against libqb -+# (it's development files), this linker script with -+# prepended INPUT command so as to refer to the actual -+# libqb library (it's numbered alias that is eventually -+# resolved to proper shared library) is masked as libqb.so, -+# this arrangement achieves the libqb's user will have -+# the discussed symbols visible alike -+# * qblog_script.la -+# - as mentioned earlier, this indirectly hooks into libtool machinery, with -+# the only true intention of injecting "-Wl," -+# into "inherited_linker_flags" libtool archive variable, from where it's -+# subsequently spread into the build process of all the internal library -+# users, assuming they have their dep arranged as "user_LIBADD=libqb.la" -+# (this also alleviates the burden on getting things right if, e.g., any -+# libqb user consumes it directly like this from its own sub-checkout tree) -+# - it indirectly, once libtool prechew the original link command -+# originally referring to this file, it turns such reference into the -+# "real" library reference (here combining libdir and old_library -+# variables within the file), also ensures libqb itself will visibly -+# expose the discussed symbols, because such references point again to -+# the (not enriched) linker script file that will get interpreted just -+# like that during the last build step of the library -+EXTRA_libqb_la_DEPENDENCIES = qblog_script.ld qblog_script.la -+EXTRA_DIST = qblog_script.ld.in qblog_script.la.in -+ - libqb_la_SOURCES = $(source_to_lint) unix.c - libqb_la_CFLAGS = $(PTHREAD_CFLAGS) - libqb_la_LIBADD = $(LTLIBOBJS) $(dlopen_LIBS) $(PTHREAD_LIBS) $(socket_LIBS) -+if NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND -+libqb_la_LIBADD += qblog_script.la -+endif - - AM_LDFLAGS = $(LDFLAGS_COPY:-Bsymbolic-functions=) - -@@ -60,6 +100,33 @@ else - endif - endif - -+qblog_script.ld: %.ld: %.ld.in -+ $(AM_V_GEN)$(CPP) -xc -I$(top_srcdir)/include -C -P $< \ -+ | sed -n "/$$(sed -n '/^[^#]/{s/[*\/]/\\\0/g;p;q}' $<)/{:r;p;n;br}" \ -+ > $@ -+ -+# find the libqb.so symlink's target, if so, try to find out, iteratively, -+# its gradually shorter forms that likewise symlinks the same target as the -+# original libqb.so path, point to that file from the linker script using -+# qblog_script.ld as a template, storing result in place of original libqb.so -+# (e.g., libqb.so := "INPUT(libqb.so.0) " [...] "SECTIONS { " [...] "}") -+# NOTE: readlink nor realpath are POSIX; not chained links ready -+# NOTE: conservative check, i.e., not per NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND -+if HAVE_GCC_ATTRIBUTE_SECTION -+install-exec-hook: qblog_script.ld -+ target=$$(ls -l "$(DESTDIR)$(libdir)/libqb.so" || :); \ -+ target=$${target#* -> }; t1_bn=$$(basename "$${target}" || :); \ -+ while test -n "$${t1_bn}"; do t2_bn=$${t1_bn%.*[0-9]*}; \ -+ test "$${t2_bn}" != libqb.so || break; \ -+ test -L "$${t2_bn}" || { t1_bn=$${t2_bn}; continue; }; \ -+ t2_target=$$(ls -l "$${t2_bn}" || break); t2_target=$${t2_target#* -> }; \ -+ test "$${t2_target}" = "$${target}" || break; \ -+ t1_bn=$${t2_bn}; done; test -n "$${t1_bn}" || \ -+ { echo "only applicable to SO symlink scheme"; exit 1; }; \ -+ echo "INPUT($${t1_bn})" > "$(DESTDIR)$(libdir)/libqb.so-t" -+ cat $< >> "$(DESTDIR)$(libdir)/libqb.so-t" -+ mv -f "$(DESTDIR)$(libdir)/libqb.so-t" "$(DESTDIR)$(libdir)/libqb.so" -+endif - - pkgconfigdir = $(libdir)/pkgconfig - pkgconfig_DATA = libqb.pc -diff --git a/lib/log.c b/lib/log.c -index bfd218f..4ed432f 100644 ---- a/lib/log.c -+++ b/lib/log.c -@@ -40,6 +40,13 @@ - #include "util_int.h" - #include - -+#if defined(QB_NEED_ATTRIBUTE_SECTION_WORKAROUND) && !defined(S_SPLINT_S) -+/* following only needed to force these symbols be global -+ with ld 2.29: https://bugzilla.redhat.com/1477354 */ -+struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_START[] = { 0 }; -+struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_STOP[] = { 0 }; -+#endif -+ - static struct qb_log_target conf[QB_LOG_TARGET_MAX]; - static uint32_t conf_active_max = 0; - static int32_t in_logger = QB_FALSE; -diff --git a/lib/qblog_script.la.in b/lib/qblog_script.la.in -new file mode 100644 -index 0000000..b475835 ---- /dev/null -+++ b/lib/qblog_script.la.in -@@ -0,0 +1,15 @@ -+# Generated by libtool -+# NOTE: above line is just to pass func_ltwrapper_script_p sanity check of -+# libtool script, as we are basically sort of abusing it so as to inject -+# our custom linker script to "private" (cf. examples) users of libqb.la -+ -+# shall rather carry a location of old_library (possibly libdir or something -+# else, but installed=no needed to suppress 'library moved' warning then) as -+# it's together (with libtool implied prefix otherwise) used for linking libqb -+libdir=@abs_builddir@ -+ -+# avoids issues with library_names (spurious rpath emitting, relink-on-install) -+old_library=qblog_script.ld -+ -+# subject of our injection into libqb.la impacting build time for private users -+inherited_linker_flags=-Wl,@abs_builddir@/qblog_script.ld -diff --git a/lib/qblog_script.ld.in b/lib/qblog_script.ld.in -new file mode 100644 -index 0000000..1f37976 ---- /dev/null -+++ b/lib/qblog_script.ld.in -@@ -0,0 +1,17 @@ -+#include -+/* GNU ld script -+ This atypical arrangement enforces global visibility of boundary symbols -+ (QB_ATTR_SECTION_START, QB_ATTR_SECTION_STOP) for the custom section -+ QB_ATTR_SECTION used for compile-time offloading of the logging call sites -+ tracking. While libqb relies on these being global, default linker from -+ binutils change the visibility as of version 2.29, making the logging -+ unusable without artificial stimulus: https://bugzilla.redhat.com/1477354 */ -+SECTIONS { -+#ifdef QB_HAVE_ATTRIBUTE_SECTION -+ QB_ATTR_SECTION : { -+ QB_ATTR_SECTION_START = .; -+ *(QB_ATTR_SECTION); -+ QB_ATTR_SECTION_STOP = .; -+ } -+#endif -+} --- -2.14.1 - diff --git a/01-Med-qblog.h-better-explanation-behaviour-of-QB_LOG_I.patch b/01-Med-qblog.h-better-explanation-behaviour-of-QB_LOG_I.patch new file mode 100644 index 0000000..41e7765 --- /dev/null +++ b/01-Med-qblog.h-better-explanation-behaviour-of-QB_LOG_I.patch @@ -0,0 +1,66 @@ +From 8bfe49d79c1b7ae1aa4b7b22b627afa40a4a08d2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= +Date: Fri, 6 Oct 2017 17:17:26 +0200 +Subject: [PATCH 1/6] Med: qblog.h: better explanation + behaviour of + QB_LOG_INIT_DATA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Based on better understanding how link-time callsite collection works, +put a better description for the macro. Also based on poor user +experience in case that feature does not work well, say because +the linker deliberately changes the previously settled visibility +of the section boundary symbols (happened in ld from binutils-2.29, +fix is forthcoming), tweak the assertion message a bit: + +- use case: + /usr/sbin/pacemakerd --features + +- before: + pacemakerd: utils.c:69: common: + Assertion `0' failed + +- after: + pacemakerd: utils.c:69: common: + Assertion `("non-empty callsite section", QB_ATTR_SECTION_START != QB_ATTR_SECTION_STOP)' failed. + +Inspired by the suggestion of Ferenc Wágner (for the subsequent +commit, actually). + +Signed-off-by: Jan Pokorný +--- + include/qb/qblog.h | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/include/qb/qblog.h b/include/qb/qblog.h +index 3cb4eef..d38449d 100644 +--- a/include/qb/qblog.h ++++ b/include/qb/qblog.h +@@ -268,11 +268,18 @@ typedef void (*qb_log_filter_fn)(struct qb_log_callsite * cs); + extern struct qb_log_callsite QB_ATTR_SECTION_START[]; + extern struct qb_log_callsite QB_ATTR_SECTION_STOP[]; + +-/* mere linker sanity check, possible future extension for internal purposes */ +-#define QB_LOG_INIT_DATA(name) \ +- void name(void); \ +- void name(void) \ +- { if (QB_ATTR_SECTION_START == QB_ATTR_SECTION_STOP) assert(0); } \ ++/* optional on-demand self-check of (1) toolchain sanity and (2) non-void ++ * (implied by the justifying existence of at least a single logging callsite ++ * ~ qb_logt invocation) employment of logging subsystem in the target binary, ++ * which is presumably assured by it's author as of relying on this macro; ++ * only effective when link-time ("run-time amortizing") callsite collection ++ * is available and may be extended in future for more in-depth self-validation ++ */ ++#define QB_LOG_INIT_DATA(name) \ ++ void name(void); \ ++ void name(void) \ ++ { assert(("non-empty callsite section", \ ++ QB_ATTR_SECTION_START != QB_ATTR_SECTION_STOP)); } \ + void __attribute__ ((constructor)) name(void); + #else + #define QB_LOG_INIT_DATA(name) +-- +2.14.2 + diff --git a/0001-build-configure-run-attribute-section-test-through-r.patch b/02-build-configure-run-attribute-section-test-through-r.patch similarity index 57% rename from 0001-build-configure-run-attribute-section-test-through-r.patch rename to 02-build-configure-run-attribute-section-test-through-r.patch index c632f87..0c276f7 100644 --- a/0001-build-configure-run-attribute-section-test-through-r.patch +++ b/02-build-configure-run-attribute-section-test-through-r.patch @@ -1,42 +1,47 @@ -From 37923941f659b1d264e33da188a1c0624cbd204b Mon Sep 17 00:00:00 2001 +From d6491970c1e050dae3fc9b65fd34e4c170ca50a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= -Date: Thu, 10 Aug 2017 17:13:32 +0200 -Subject: [PATCH 1/2] build: configure: run attribute section test through +Date: Fri, 6 Oct 2017 17:17:26 +0200 +Subject: [PATCH 2/6] build: configure: run attribute section test through run-time assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -It unclear why the apparently run-time test hasn't been set to that -effect, but only the compilability was tested so far. +It's unclear why the apparently run-time test hasn't been set to that +effect, mere compilability was tested so far. + +Also, based on feedback by Ferenc Wágner, unify and increase usability +of the run-time error signalling through assertions. Signed-off-by: Jan Pokorný --- - configure.ac | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) + configure.ac | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac -index 5ba4f99..fd37466 100644 +index 22630ba..727b8f0 100644 --- a/configure.ac +++ b/configure.ac -@@ -620,15 +620,18 @@ AC_SUBST(HAVE_SLOW_TESTS) +@@ -620,15 +620,17 @@ AC_SUBST(HAVE_SLOW_TESTS) if test "x${GCC}" = xyes; then AC_MSG_CHECKING([whether GCC supports __attribute__((section()) + ld supports orphan sections]) if test "x${ac_cv_link_attribute_section}" = x ; then - AC_TRY_LINK([#include - extern void * __start___verbose, * __stop___verbose;], - [static int my_var __attribute__((section("__verbose"))) = 5; +- if (__start___verbose == __stop___verbose) assert(0); +- if (my_var == 5) return 0; +- else return -1; +- ], +- [gcc_has_attribute_section=yes], +- [gcc_has_attribute_section=no]) + AC_TRY_RUN( + AC_LANG_PROGRAM( + [[#include + extern void * __start___verbose, * __stop___verbose;]], + [[static int my_var __attribute__((section("__verbose"))) = 5; - if (__start___verbose == __stop___verbose) assert(0); - if (my_var == 5) return 0; - else return -1; -- ], -- [gcc_has_attribute_section=yes], -- [gcc_has_attribute_section=no]) ++ assert(("non-empty data section", __start___verbose != __stop___verbose)); ++ assert(("no data section value loss", my_var == 5)); + ]]), + [gcc_has_attribute_section=yes], + [gcc_has_attribute_section=no] @@ -45,5 +50,5 @@ index 5ba4f99..fd37466 100644 gcc_has_attribute_section=${ac_cv_link_attribute_section} fi -- -2.14.0 +2.14.2 diff --git a/03-tests-new-sort-of-tests-dubbed-functional-cover-link.patch b/03-tests-new-sort-of-tests-dubbed-functional-cover-link.patch new file mode 100644 index 0000000..3bcf1d5 --- /dev/null +++ b/03-tests-new-sort-of-tests-dubbed-functional-cover-link.patch @@ -0,0 +1,964 @@ +From d9ed1dbcd9d58cac8573b75e6db323757f39e27b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= +Date: Fri, 6 Oct 2017 17:17:26 +0200 +Subject: [PATCH 3/6] tests: new sort of tests dubbed "functional", cover + linker vs. logging +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These are for quick manual sanity checking, assuming the target audience +-- maintainers -- are clear on the context of use and the purpose +(perhaps with the help of static files for comparison and/or additional +checking harness, usually available through "make check", but not to be +confused with regular unit + broader tests). These test are meant to be +compiled on demand only, not during the standard building routine, for +which a trick leveraging GNUmakefile-Makefile precedence with GNU make +was devised. + +The respective new tests are meant to simulate logging variants in two +different library consumption models: + a. regular: linking against system-wide library + b. developmental: consuming library from a local sub-checkout tree, + using libtool conventions and hence attaching the + library through libqb.la intermediate library + descriptor of libtool +and between up to three possibly affected logging system participants +(discrete compilation units): + 1. libqb itself will emit log messages in boundary conditions or + for tracing purposes + 2. client program that consumes libqb's logging API directly + 3. ditto, but the client program furthermore links with a library + (referred to as "interlib") that itself exercises the logging + API (it's also linked with libqb) -- through induction, this + should cover whole class of N interlib cases + +Especially the latter perspective makes for a test matrix to possibly +(hopefully) demonstrate a fix allowing to cope with the changed +behaviour of ld from binutils 2.29+ wrt. boundaries denoting symbols for +a (custom) orphan section that are no longer externally visible. Such +commit is in the pipeline... + +Developmental consumption model (a.) is now also tested automatically +in Travis CI runs and as a part of %check within upstream-suggested +libqb.spec for RPM packaging, whereas the regular one (b.) serves as +a building block for new new log_test_mock.sh runner of said test matrix +-- it iterates through all the possible permutations of linker-imposed +implicit visibility of mentioned symbols between various affected +linkage sides (see 1. - 3. above) so as to demonstrate a/ the impact +of the problem (see table below), and subsequently b/ that the fix is +effective in all these situations (updated table will be provided as +well) once it lands. + +Current state for this matrix, in which participants 1. - 3. map like: + 1. ~ libqb(Y) + 2. ~ "direct" + 3. ~ libX(Y) [a.k.a. interlib] +and where "X(Y)" denotes "X linked with linker Y": + X(a) .. ld.bfd < 2.29 + X(b) .. ld.bfd = 2.29 (and likely on), +goes like this: + ++=========+=========+=========+=========+=========+=========+=========+ +#client(x)# libqb(a) usage # libqb(b) usage # +# vvv #---------+---------+---------+---------+---------+---------+ +# V # direct | libX(a) : libX(b) # direct | libX(a) : libX(b) # ++=========+=========+=========+=========+=========+=========+=========+ +# x = a # OK | OK : BAD[*2] # BAD[*1] | BAD[*D] : BAD[*3] # +# x = b # BAD[*A] | BAD[*B] : BAD[*C] # BAD[*1] | BAD[*C] : BAD[*3] # ++=========+=========+=========+=========+=========+=========+=========+ + +[*1] client logging not working +[*2] interlib logging not working +[*3] both client and interlib logging not working + +[*A] boils down to [*1], unless QB_LOG_INIT_DATA used on client side, + which fails on 'non-empty callsite section' assertion +[*B] boils down to [*1], unless QB_LOG_INIT_DATA used on interlib side, + which fails on 'non-empty callsite section' assertion +[*C] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side, + which fails on 'non-empty callsite section' assertion +[*D] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side, + which makes it boil down just to [*1] (hypothesis: mere internal + self-reference to the section's boundary symbols makes them + overcome some kind of garbage collection at the linkage stage, + so they are exposed even they wouldn't be otherwise as demonstrated + with the initial, plain case of [*3]) + +Note: as observed with [*D] case (libqb linked with ld.bfd < 2.29 +whereas interlib and its client linked with ld.bfd = 2.29), the exact +availability of a working logging doesn't depend solely on the linkers +in question, but generally (further investigation out of scope) the +conclusion is that when 2.29+ ld.bfd is involved somewhere in the chain +of logging-related discrete compilation units, also (self-)referencing +of the section's boundary denoting symbols is a deciding factor whether +particular logging source will be honored. This may be a result of +some internal linkage garbage collection mechanisms involved. +Anyway, it is supposed that the fix to broken-by-linkage logging can be +proclaimed complete once all combinations pass barring QB_LOG_INIT_DATA +usage (incurring the mentioned active referential use of the symbols), +along with a spin using it everywhere for good measure. + +Signed-off-by: Jan Pokorný +--- + configure.ac | 7 +- + libqb.spec.in | 3 +- + tests/Makefile.am | 3 + + tests/functional/GNUmakefile | 20 ++ + tests/functional/Makefile.am | 23 +++ + tests/functional/log.am | 49 +++++ + tests/functional/log_client.c | 86 ++++++++ + tests/functional/log_client.err | 2 + + tests/functional/log_external/Makefile.am | 23 +++ + tests/functional/log_interlib.c | 68 +++++++ + tests/functional/log_interlib_client.c | 64 ++++++ + tests/functional/log_interlib_client.err | 4 + + tests/functional/log_internal/Makefile.am | 23 +++ + tests/functional/log_test_client.sh | 22 +++ + tests/functional/log_test_interlib_client.sh | 22 +++ + tests/functional/log_test_mock.sh | 283 +++++++++++++++++++++++++++ + 18 files changed, 700 insertions(+), 2 deletions(-) + create mode 100644 tests/functional/GNUmakefile + create mode 100644 tests/functional/Makefile.am + create mode 100644 tests/functional/log.am + create mode 100644 tests/functional/log_client.c + create mode 100644 tests/functional/log_client.err + create mode 100644 tests/functional/log_external/Makefile.am + create mode 100644 tests/functional/log_interlib.c + create mode 100644 tests/functional/log_interlib_client.c + create mode 100644 tests/functional/log_interlib_client.err + create mode 100644 tests/functional/log_internal/Makefile.am + create mode 100755 tests/functional/log_test_client.sh + create mode 100755 tests/functional/log_test_interlib_client.sh + create mode 100755 tests/functional/log_test_mock.sh + +diff --git a/configure.ac b/configure.ac +index 727b8f0..db7bc68 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -13,7 +13,7 @@ AC_CONFIG_SRCDIR([lib/ringbuffer.c]) + AC_CONFIG_HEADERS([include/config.h include/qb/qbconfig.h]) + AC_USE_SYSTEM_EXTENSIONS + +-AM_INIT_AUTOMAKE([-Wno-portability dist-xz]) ++AM_INIT_AUTOMAKE([-Wno-portability dist-xz subdir-objects]) + dnl automake >= 1.11 offers --enable-silent-rules for suppressing the output from + dnl normal compilation. When a failure occurs, it will then display the full + dnl command line +@@ -715,6 +715,9 @@ AC_CONFIG_FILES([Makefile + lib/libqb.pc + tools/Makefile + tests/Makefile ++ tests/functional/Makefile ++ tests/functional/log_external/Makefile ++ tests/functional/log_internal/Makefile + tests/test.conf + examples/Makefile + docs/Makefile +@@ -722,6 +725,8 @@ AC_CONFIG_FILES([Makefile + docs/html.dox + docs/man.dox]) + ++AC_CONFIG_LINKS([tests/functional/GNUmakefile:tests/functional/GNUmakefile]) ++ + AC_OUTPUT + + AC_MSG_RESULT([]) +diff --git a/libqb.spec.in b/libqb.spec.in +index 8320982..cd7fd0f 100644 +--- a/libqb.spec.in ++++ b/libqb.spec.in +@@ -31,7 +31,8 @@ make %{?_smp_mflags} + + %if 0%{?with_check} + %check +-VERBOSE=1 make check ++make V=1 check \ ++ && make -C tests/functional/log_internal V=1 check + %endif + + %install +diff --git a/tests/Makefile.am b/tests/Makefile.am +index fe54741..df1af81 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -20,6 +20,9 @@ + MAINTAINERCLEANFILES = Makefile.in + EXTRA_DIST = + CLEANFILES = ++ ++SUBDIRS = functional ++ + AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include + + noinst_PROGRAMS = bmc bmcpt bms rbreader rbwriter \ +diff --git a/tests/functional/GNUmakefile b/tests/functional/GNUmakefile +new file mode 100644 +index 0000000..1b9de81 +--- /dev/null ++++ b/tests/functional/GNUmakefile +@@ -0,0 +1,20 @@ ++all check: ++ # do not trigger automatically, it's for on-demand use ++ @echo "Use 'make $@' within particular subdirectories" ++install: force ++ # definitely not desired to install anything from this subtree ++distclean: ++ # following is a nasty hack to keep "make distclean" succeeding ++ # (problem mostly arises from shared object files and hence shared ++ # compiler-generated makefile includes which are swiped when ++ # processing one subdir and missing as hard error for the other) ++ @$(MAKE) -C log_external $@ ++ @mkdir .deps ++ @touch .deps/log_client.Po .deps/log_interlib.Plo .deps/log_interlib_client.Po ++ @$(MAKE) -C log_internal $@ ++ @$(MAKE) -f Makefile $@ SUBDIRS= ++%: force ++ @$(MAKE) -f Makefile $@ ++force: ; ++ ++.PHONY: check distclean force install +diff --git a/tests/functional/Makefile.am b/tests/functional/Makefile.am +new file mode 100644 +index 0000000..72f551e +--- /dev/null ++++ b/tests/functional/Makefile.am +@@ -0,0 +1,23 @@ ++# Copyright 2017 Red Hat, Inc. ++# ++# Authors: Jan Pokorny ++# ++# This file is part of libqb. ++# ++# libqb is free software: you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation, either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# libqb is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with libqb. If not, see . ++ ++MAINTAINERCLEANFILES = Makefile.in ++EXTRA_DIST = GNUmakefile log_client.err log_interlib_client.err \ ++ log_test_client.sh log_test_interlib_client.sh log_test_mock.sh ++SUBDIRS = log_external log_internal +diff --git a/tests/functional/log.am b/tests/functional/log.am +new file mode 100644 +index 0000000..5fe1ae7 +--- /dev/null ++++ b/tests/functional/log.am +@@ -0,0 +1,49 @@ ++# Copyright 2017 Red Hat, Inc. ++# ++# Author: Jan Pokorny ++# ++# This file is part of libqb. ++# ++# libqb is free software: you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation, either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# libqb is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with libqb. If not, see . ++ ++MAINTAINERCLEANFILES = Makefile.in ++CLEANFILES = log_client.err.real log_interlib_client.err.real ++ ++AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include ++ ++noinst_PROGRAMS = log_client log_interlib_client ++# cannot use {check,noinst}_LTLIBRARIES because it leads to solely static lib ++# (this won't get installed anyway, thanks to GNUmakefile rule) ++lib_LTLIBRARIES = liblog_inter.la ++ ++log_client_SOURCES = ../log_client.c ++# log_client_LDFLAGS/log_client_LDADD to be delivered by the base Makefile.am ++ ++liblog_inter_la_SOURCES = ../log_interlib.c ++liblog_inter_la_LDFLAGS = -shared ++# liblog_inter_la_LIBADD to be delivered by the base Makefile.am ++ ++log_interlib_client_SOURCES = ../log_interlib_client.c ++# this transitively shares link dependencies with liblog_inter.la itself ++log_interlib_client_LDADD = $(builddir)/liblog_inter.la ++ ++# actual 'make check' auxiliary definitions ++TESTS = ../log_test_client.sh ../log_test_interlib_client.sh ++TEST_EXTENSIONS = .sh ++log_test.log: $(check_PROGRAMS) ++ ++../log_test_client.log: log_client ++../log_test_interlib_client.log: log_interlib_client ++ ++# vim: ft=automake +diff --git a/tests/functional/log_client.c b/tests/functional/log_client.c +new file mode 100644 +index 0000000..aa6ebe1 +--- /dev/null ++++ b/tests/functional/log_client.c +@@ -0,0 +1,86 @@ ++/* ++ * Copyright 2017 Red Hat, Inc. ++ * ++ * All rights reserved. ++ * ++ * Author: Jan Pokorny ++ * ++ * This file is part of libqb. ++ * ++ * libqb is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation, either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * libqb is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with libqb. If not, see . ++ */ ++#include "os_base.h" ++#include ++ ++#ifndef NSELFCHECK ++QB_LOG_INIT_DATA(linker_contra_log); ++#endif ++ ++static const char * ++my_tags_stringify(uint32_t tags) ++{ ++ if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) { ++ return "libqb"; ++ } else { ++ return "MAIN"; ++ } ++} ++ ++int32_t ++main(int32_t argc, char *argv[]) ++{ ++ int tmpfile_fd; ++ struct stat tmpfile_stat; ++ char *tmpfile_buf = strdup("linker-log-XXXXXX"); ++ ++ qb_log_init("linker-contra-log", LOG_USER, LOG_INFO); ++ qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE); ++ qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, ++ QB_LOG_FILTER_FILE, "*", LOG_DEBUG); ++ qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); ++ ++ qb_log_tags_stringify_fn_set(my_tags_stringify); ++ qb_log_format_set(QB_LOG_STDERR, "[%5g|%p] %f:%l:%b"); ++ ++#if 0 ++ printf("--\n"); ++ qb_log_callsites_dump(); ++ printf("--\n"); ++#endif ++ ++ /* Casual test of "user-space" logging. */ ++ qb_log(LOG_DEBUG, "hello"); ++ ++ /* And now of "library-space" logging, i.e., let libqb generated ++ an error message on its own behalf, first to see if it will be ++ logged at all, second if it will be distinguished properly. ++ The trigger here is as simple as trying to print non-existing ++ blackbox file. */ ++ tmpfile_fd = mkstemp(tmpfile_buf); ++ if (tmpfile_fd == -1) { ++ qb_perror(LOG_ERR, "creating temporary file"); ++ exit(EXIT_FAILURE); ++ } ++ unlink(tmpfile_buf); ++ close(tmpfile_fd); ++#if 0 ++ if (stat(tmpfile_buf, &tmpfile_stat) == -1) { ++ qb_perror(LOG_ERR, "stat'ing nonexistent temporary file"); ++ exit(EXIT_FAILURE); ++ } ++#endif ++ qb_log_blackbox_print_from_file(tmpfile_buf); ++ free(tmpfile_buf); ++ qb_log_fini(); ++} +diff --git a/tests/functional/log_client.err b/tests/functional/log_client.err +new file mode 100644 +index 0000000..0ae7665 +--- /dev/null ++++ b/tests/functional/log_client.err +@@ -0,0 +1,2 @@ ++[MAIN |debug] ../log_client.c:63:hello ++[libqb|error] log_blackbox.c:196:qb_log_blackbox_print_from_file: No such file or directory (2) +diff --git a/tests/functional/log_external/Makefile.am b/tests/functional/log_external/Makefile.am +new file mode 100644 +index 0000000..36aa0af +--- /dev/null ++++ b/tests/functional/log_external/Makefile.am +@@ -0,0 +1,23 @@ ++# Copyright 2017 Red Hat, Inc. ++# ++# Author: Jan Pokorny ++# ++# This file is part of libqb. ++# ++# libqb is free software: you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation, either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# libqb is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with libqb. If not, see . ++ ++include ../log.am ++ ++log_client_LDFLAGS = -lqb ++liblog_inter_la_LIBADD = -lqb +diff --git a/tests/functional/log_interlib.c b/tests/functional/log_interlib.c +new file mode 100644 +index 0000000..498f82c +--- /dev/null ++++ b/tests/functional/log_interlib.c +@@ -0,0 +1,68 @@ ++/* ++ * Copyright 2017 Red Hat, Inc. ++ * ++ * All rights reserved. ++ * ++ * Author: Jan Pokorny ++ * ++ * This file is part of libqb. ++ * ++ * libqb is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation, either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * libqb is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with libqb. If not, see . ++ */ ++#include "os_base.h" ++#include ++ ++#ifndef NSELFCHECK ++QB_LOG_INIT_DATA(linker_contra_log_lib); ++#endif ++ ++void foo(void); ++ ++void ++foo(void) ++{ ++ int tmpfile_fd; ++ struct stat tmpfile_stat; ++ char *tmpfile_buf = strdup("linker-log-XXXXXX"); ++ ++#if 0 ++ printf("--\n"); ++ qb_log_callsites_dump(); ++ printf("--\n"); ++#endif ++ ++ /* Casual test of "user-space" logging. */ ++ qb_log(LOG_INFO, "hello"); ++ ++ /* And now of "library-space" logging, i.e., let libqb generated ++ an error message on its own behalf, first to see if it will be ++ logged at all, second if it will be distinguished properly. ++ The trigger here is as simple as trying to print non-existing ++ blackbox file. */ ++ tmpfile_fd = mkstemp(tmpfile_buf); ++ if (tmpfile_fd == -1) { ++ qb_perror(LOG_ERR, "creating temporary file"); ++ exit(EXIT_FAILURE); ++ } ++ unlink(tmpfile_buf); ++ close(tmpfile_fd); ++#if 0 ++ if (stat(tmpfile_buf, &tmpfile_stat) == -1) { ++ qb_perror(LOG_ERR, "stat'ing nonexistent temporary file"); ++ exit(EXIT_FAILURE); ++ } ++#endif ++ qb_log_blackbox_print_from_file(tmpfile_buf); ++ free(tmpfile_buf); ++} +diff --git a/tests/functional/log_interlib_client.c b/tests/functional/log_interlib_client.c +new file mode 100644 +index 0000000..c669703 +--- /dev/null ++++ b/tests/functional/log_interlib_client.c +@@ -0,0 +1,64 @@ ++/* ++ * Copyright 2017 Red Hat, Inc. ++ * ++ * All rights reserved. ++ * ++ * Author: Jan Pokorny ++ * ++ * This file is part of libqb. ++ * ++ * libqb is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation, either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * libqb is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with libqb. If not, see . ++ */ ++#include "os_base.h" ++#include ++ ++#ifndef NSELFCHECK ++QB_LOG_INIT_DATA(linker_contra_log_lib_user); ++#endif ++ ++void foo(void); ++ ++static const char * ++my_tags_stringify(uint32_t tags) ++{ ++ if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) { ++ return "libqb"; ++ } else { ++ return "MAIN"; ++ } ++} ++ ++int ++main(int argc, char *argv[]) ++{ ++ qb_log_init("linker-contra-log", LOG_USER, LOG_INFO); ++ qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE); ++ qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, ++ QB_LOG_FILTER_FILE, "*", LOG_DEBUG); ++ qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); ++ ++ qb_log_tags_stringify_fn_set(my_tags_stringify); ++ qb_log_format_set(QB_LOG_STDERR, "[%5g|%p] %f:%l:%b"); ++ ++#if 0 ++ printf("--\n"); ++ qb_log_callsites_dump(); ++ printf("--\n"); ++#endif ++ ++ qb_log(LOG_INFO, "BEFORE"); ++ foo(); ++ qb_log(LOG_INFO, "AFTER"); ++ qb_log_fini(); ++} +diff --git a/tests/functional/log_interlib_client.err b/tests/functional/log_interlib_client.err +new file mode 100644 +index 0000000..486071a +--- /dev/null ++++ b/tests/functional/log_interlib_client.err +@@ -0,0 +1,4 @@ ++[MAIN |info] ../log_interlib_client.c:60:BEFORE ++[MAIN |info] ../log_interlib.c:46:hello ++[libqb|error] log_blackbox.c:196:qb_log_blackbox_print_from_file: No such file or directory (2) ++[MAIN |info] ../log_interlib_client.c:62:AFTER +diff --git a/tests/functional/log_internal/Makefile.am b/tests/functional/log_internal/Makefile.am +new file mode 100644 +index 0000000..697cee2 +--- /dev/null ++++ b/tests/functional/log_internal/Makefile.am +@@ -0,0 +1,23 @@ ++# Copyright 2017 Red Hat, Inc. ++# ++# Author: Jan Pokorny ++# ++# This file is part of libqb. ++# ++# libqb is free software: you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation, either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# libqb is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with libqb. If not, see . ++ ++include ../log.am ++ ++log_client_LDADD = $(top_builddir)/lib/libqb.la ++liblog_inter_la_LIBADD = $(top_builddir)/lib/libqb.la +diff --git a/tests/functional/log_test_client.sh b/tests/functional/log_test_client.sh +new file mode 100755 +index 0000000..875871e +--- /dev/null ++++ b/tests/functional/log_test_client.sh +@@ -0,0 +1,22 @@ ++#!/bin/sh ++# Copyright 2017 Red Hat, Inc. ++# ++# Author: Jan Pokorny ++# ++# This file is part of libqb. ++# ++# libqb is free software: you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation, either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# libqb is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with libqb. If not, see . ++ ++./log_client >/dev/null 2>log_client.err.real ++diff -u ../log_client.err log_client.err.real +diff --git a/tests/functional/log_test_interlib_client.sh b/tests/functional/log_test_interlib_client.sh +new file mode 100755 +index 0000000..59c5555 +--- /dev/null ++++ b/tests/functional/log_test_interlib_client.sh +@@ -0,0 +1,22 @@ ++#!/bin/sh ++# Copyright 2017 Red Hat, Inc. ++# ++# Author: Jan Pokorny ++# ++# This file is part of libqb. ++# ++# libqb is free software: you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation, either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# libqb is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with libqb. If not, see . ++ ++./log_interlib_client >/dev/null 2>log_interlib_client.err.real ++diff -u ../log_interlib_client.err log_interlib_client.err.real +diff --git a/tests/functional/log_test_mock.sh b/tests/functional/log_test_mock.sh +new file mode 100755 +index 0000000..cc3519d +--- /dev/null ++++ b/tests/functional/log_test_mock.sh +@@ -0,0 +1,283 @@ ++#!/bin/sh ++# Copyright 2017 Red Hat, Inc. ++# ++# Author: Jan Pokorny ++# ++# This file is part of libqb. ++# ++# libqb is free software: you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation, either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# libqb is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with libqb. If not, see . ++ ++# Given the source RPM for libqb, this will run through the basic test matrix ++# so as to figure out the outcomes for particular linker (pre-2.29 and 2.29+ ++# differing in visibility of orphan section delimiting boundary symbols and ++# hence possibly causing harm to the logging facility of libqb) being used ++# for particular part of the composite logging system (libqb itself, ++# it's direct client / (client library + it's own client that uses logging) ++# as well). While this is tailored to Fedora, it should be possible to ++# run this testsuite wherever following is present: ++# ++# - rpm (for parsing archive name embedded in libqb.src.rpm [note that ++# rpm2cpio is part of rpm package as well] because the extracted dir ++# follows the same naming, which we need to know) ++# - mock + dependencies + fedora-27-${arch} configuration for mock ++# (or whatever other configuration if some variables below are ++# changed appropriately) ++# - koji + dependencies (but binutils packages can be precached when ++# downloaded from https://koji.fedoraproject.org/ manually) ++# - internet connection (but see the above statement for koji, and ++# possibly the full package set within the build'n'test underlying ++# container can be precached without further details on "how") ++# - commons (coreutils, findutils, sed, ...) ++# ++# The testsuite will not mangle with your host system as mock spawns ++# it's somewhat private container for be worked with under the hood. ++# ++# Note that in order not to get mad when entering the root password anytime ++# mock is invoked, you can add the user initiating the test run to the ++# 'mock' group. Be aware of the associated security risks, though: ++# https://github.com/rpm-software-management/mock/wiki#setup ++ ++set -eu ++ ++# change following as suitable ++ ++arch=x86_64 ++mock_args="-r fedora-27-${arch}" ++pkg_binutils_228=binutils-2.28-14.fc27 ++pkg_binutils_229=binutils-2.29-6.fc27 ++ ++# ++# prettified reporters ++# ++ ++do_progress () { printf "\x1b[7m%s\x1b[0m\n" "$*"; } ++do_info () { printf "\x1b[36mINFO: %s\x1b[0m\n" "$*"; } ++do_warn () { printf "\x1b[31mWARNING: %s\x1b[0m\n" "$*"; } ++do_die () { printf "\x1b[31mFATAL: %s\x1b[0m\n" "$*"; exit 1; } ++ ++# ++# actual building blocks ++# ++ ++# $1, ... $N: packages (and possibly related subpackages) to be downloaded ++do_download () { ++ while test $# -gt 0; do ++ if test -d "_pkgs/$1" 2>/dev/null; then ++ do_info "$1 already downloaded" ++ shift; continue ++ fi ++ mkdir -p "_pkgs/$1" ++ ( cd "_pkgs/$1" && koji download-build --arch="${arch}" "$1" ) ++ shift ++ done ++} ++ ++# $1, ... $N: descriptors of packages to be installed ++do_install () { ++ while test $# -gt 0; do ++ if test -d "_pkgs/$1" 2>/dev/null; then ++ do_install_inner "_pkgs/$1"/*.rpm ++ else ++ do_warn "$1 is not downloaded, hence skipped" ++ fi ++ shift ++ done ++} ++ ++# $1, ... $N: concrete packages to be installed ++do_install_inner () { ++ _remove_cmd="mock ${mock_args} -- shell \"rpm --nodeps --erase" ++ _install_cmd="mock ${mock_args}" ++ while test $# -gt 0; do ++ case "$1" in ++ *.src.rpm|*-debuginfo*|*-debugsource*) ;; ++ *) ++ _pkg_name="$(basename "$1" | sed 's|\(-[0-9].*\)||')" ++ _remove_cmd="${_remove_cmd} \'${_pkg_name}\'" ++ _install_cmd="${_install_cmd} --install \"$1\"";; ++ esac ++ shift ++ done ++ eval "${_remove_cmd}\"" || : # extra quotation mark intentional ++ eval "${_install_cmd}" ++} ++ ++# $1: full path of srpm to be rebuilt ++# $2: %{dist} macro for rpmbuild (distinguishing the builds) ++do_buildsrpm () { ++ _pkg_descriptor="$(basename "$1" | sed 's|\.src\.rpm$||')" ++ # need to prune due to possible duplicates caused by differing %{dist} ++ rm -f -- "_pkgs/${_pkg_descriptor}"/* ++ mock ${mock_args} -Nn --define "dist $2" --define '_without_check 1' \ ++ --resultdir "_pkgs/${_pkg_descriptor}" --rebuild "$1" ++} ++ ++# $1: full path srpm to be rebuilt ++# $2: extra (presumably) variable assignments for the make goal invocation ++do_compile_interlib () { ++ mock ${mock_args} --shell \ ++ "find \"builddir/build/BUILD/$1/tests/functional\" \ ++ \( -name log_internal -o -name '*.c' \) -prune \ ++ -o -name '*liblog_inter*' \ ++ -exec rm -- {} \;" ++ mock ${mock_args} --shell "( cd \"builddir/build/BUILD/$1\"; ./configure )" ++ mock ${mock_args} --shell \ ++ "make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \ ++ liblog_inter.la $2" ++} ++ ++# $1: full path srpm to be rebuilt ++# $2: which type of client to work with (client/interclient) ++# $3: base (on-host) directory for test results ++# $4: output file to capture particular test result ++# $5: extra (presumably) variable assignments for the make goal invocation ++do_compile_and_test_client () { ++ _result=$4 ++ case "$2" in ++ interclient) ++ _logfile=log_test_interlib_client ++ mock ${mock_args} --shell \ ++ "find \"builddir/build/BUILD/$1/tests/functional\" \ ++ \( -name log_internal -o -name '*.err' -o -name '*.c' \) -prune \ ++ -o \( -name '*log_interlib_client*' -o -name \"${_logfile}.log\" \) \ ++ -exec rm -- {} \;" ++ ;; ++ client|*) ++ _logfile=log_test_client ++ mock ${mock_args} --shell \ ++ "find \"builddir/build/BUILD/$1/tests/functional\" \ ++ \( -name log_internal -o -name '*.err' -o -name '*.c' \) -prune \ ++ -o \( -name '*log_client*' -o -name \"${_logfile}.log\" \) \ ++ -exec rm -- {} \;" ++ ;; ++ esac ++ mock ${mock_args} --shell "( cd \"builddir/build/BUILD/$1\"; ./configure )" ++ mock ${mock_args} --shell \ ++ "make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \ ++ check-TESTS \"TESTS=../${_logfile}.sh\" $5" \ ++ && _result="${_result}_good" \ ++ || _result="${_result}_bad" ++ mock ${mock_args} --copyout \ ++ "builddir/build/BUILD/$1/tests/functional/log_external/test-suite.log" \ ++ "$3/${_result}" ++} ++ ++do_shell () { ++ mock ${mock_args} --shell ++} ++ ++# $1, ... $N: "argv" ++do_proceed () { ++ ++ _makevars= ++ case "$1" in ++ shell) shift; do_shell "$@"; return;; ++ -n) shift; _makevars='CPPFLAGS=-DNSELFCHECK';; ++ esac ++ ++ test -s "$1" || do_die "Not an input file: $1" ++ _libqb_descriptor_path="$1" ++ _libqb_descriptor="$(basename "${_libqb_descriptor_path}" \ ++ | sed 's|\.src\.rpm$||')" ++ _libqb_descriptor_archive="$(rpm -q --qf '[%{FILENAMES}\n]' \ ++ -p "${_libqb_descriptor_path}" \ ++ | sed -n '/\.tar/{s|\.tar\.[^.]*$||;p;q}')" ++ ++ _resultsdir="_results/$(date '+%y%m%d_%H%M%S')_${_libqb_descriptor}" ++ test -z "${_makevars}" || _resultsdir="${_resultsdir}_sc" ++ mkdir -p "${_resultsdir}" ++ rm -f -- "${_resultsdir}/*" ++ ++ _dist= ++ _outfile= ++ _outfile_client= ++ _outfile_qb= ++ ++ do_download "${pkg_binutils_228}" "${pkg_binutils_229}" ++ ++ for _pkg_binutils_libqb in "${pkg_binutils_228}" "${pkg_binutils_229}"; do ++ ++ case "${_pkg_binutils_libqb}" in ++ ${pkg_binutils_228}) _outfile_qb="qb+"; _dist=.binutils228;; ++ ${pkg_binutils_229}) _outfile_qb="qb-"; _dist=.binutils229;; ++ *) _outfile_qb="?";; ++ esac ++ ++ do_progress "installing ${_pkg_binutils_libqb} so as to build" \ ++ " libqb [${_outfile_qb}]" ++ do_install "${_pkg_binutils_libqb}" ++ ++ do_progress "building ${_libqb_descriptor_path} with" \ ++ " ${_pkg_binutils_libqb} [${_outfile_qb}]" ++ do_buildsrpm "${_libqb_descriptor_path}" "${_dist}" ++ ++ do_progress "installing ${_libqb_descriptor}-based packages" \ ++ " built with ${_pkg_binutils_libqb} [${_outfile_qb}]" ++ do_install "${_libqb_descriptor}" ++ ++ for _pkg_binutils_interlib in none "${pkg_binutils_228}" "${pkg_binutils_229}"; do ++ ++ case "${_pkg_binutils_interlib}" in ++ none) _outfile="${_outfile_qb}";; ++ ${pkg_binutils_228}) _outfile="${_outfile_qb}_il+";; ++ ${pkg_binutils_229}) _outfile="${_outfile_qb}_il-";; ++ *) _outfile="${_outfile_qb}_?";; ++ esac ++ ++ case "${_pkg_binutils_interlib}" in ++ none) ;; ++ *) ++ do_progress "installing ${_pkg_binutils_interlib}" \ ++ " so as to build interlib [${_outfile}]" ++ do_install "${_pkg_binutils_interlib}" ++ ++ do_progress "building interlib with ${_libqb_descriptor_archive}" \ ++ " + ${_pkg_binutils_interlib} [${_outfile}]" ++ do_compile_interlib "${_libqb_descriptor_archive}" "${_makevars}" ++ ;; ++ esac ++ ++ for _pkg_binutils_client in "${pkg_binutils_228}" "${pkg_binutils_229}"; do ++ ++ _client=client ++ test "${_pkg_binutils_interlib}" = none || _client=interclient ++ ++ case "${_pkg_binutils_client}" in ++ ${pkg_binutils_228}) _outfile_client="${_outfile}_c+";; ++ ${pkg_binutils_229}) _outfile_client="${_outfile}_c-";; ++ *) _outfile_client="${_outfile}_?";; ++ esac ++ ++ do_progress "installing ${_pkg_binutils_client}" \ ++ " so as to build ${_client} [${_outfile_client}]" ++ do_install "${_pkg_binutils_client}" ++ do_progress "building ${_client} with ${_libqb_descriptor_archive}" \ ++ " + ${_pkg_binutils_client} [${_outfile_client}]" ++ do_compile_and_test_client "${_libqb_descriptor_archive}" \ ++ "${_client}" "${_resultsdir}" \ ++ "${_outfile_client}" "${_makevars}" ++ done ++ done ++ done ++} ++ ++test $# -eq 0 \ ++ && printf '%s\n %s\n %s\n %s\n %s\n %s\n' \ ++ "usage: $0 {[-n] | shell}" \ ++ "- use '-n' to suppress optional self-check (\"see whole story\")" \ ++ "- 'make -C ../.. srpm' (or so) can generate the requested input" \ ++ " (in that case, apparently, refer to '../../libqb-X.src.rpm')" \ ++ "- _pkgs dir caches (intermediate or not) packages to work with" \ ++ "- results stored in '_results/_[_]'" \ ++ || do_proceed "$@" +-- +2.14.2 + diff --git a/04-Med-add-extra-run-time-client-side-sanity-check-that.patch b/04-Med-add-extra-run-time-client-side-sanity-check-that.patch new file mode 100644 index 0000000..fe7ad5b --- /dev/null +++ b/04-Med-add-extra-run-time-client-side-sanity-check-that.patch @@ -0,0 +1,257 @@ +From 82835b453ac212937592c5a47e992d70b6f2d82b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= +Date: Fri, 6 Oct 2017 17:17:26 +0200 +Subject: [PATCH 4/6] Med: add extra run-time client-side sanity check that + logging will work +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The table at the bottom concludes how the test matrix overview +introduced with a message for the preceding commit (also introducing +log_test_mock.sh runner which got reused here) looks as of this +refreshed sanity check, once it (QB_LOG_INIT_DATA macro) gets applied +(meaning "for non-libqb logging participants" so as not complicate +the matrix further). + +Note that for libqb users, this implies a new link dependency on libdl, +because they may opt-in for refreshed QB_LOG_INIT_DATA sanity check that +calls out to dlopen/dlsym/dladdr directly in case of "attribute section" +being available for the particular platform, and hence immediately needs +those symbols resolved in link time. Hence, add this conditional link +dependency to libqb.pc pkg-config file under Libs variable -- we +actually restore the occurrence of "-ldl" there as it used to be present +until commit 56754d0. While doing so, also move immediate link +dependencies of libqb (if any, currently not but that may be +a regression arising from the cleanup related to the mentioned commit) +represented with the LIBS autoconf variable under Libs.private variable +in libqb.pc, where it belongs per pkg-config documentation. + +The promised table follows, but first as a recap, "X(Y)" denotes +"X linked with linker Y": + X(a) .. ld.bfd < 2.29 + X(b) .. ld.bfd = 2.29 (and likely on) + +goes like this (values in denote non-trivial change +[not mere rewording] introduced as of this commit, in comparison to +the table stated in the preceding commit): + ++=========+=========+=========+=========+=========+=========+=========+ +#client(x)# libqb(a) usage # libqb(b) usage # +# vvv #---------+---------+---------+---------+---------+---------+ +# V # direct | libX(a) : libX(b) # direct | libX(a) : libX(b) # ++=========+=========+=========+=========+=========+=========+=========+ +# x = a # OK | OK : BAD[*2] #|:# +# x = b # BAD[*A] | BAD[*B] : BAD[*C] #|:# ++=========+=========+=========+=========+=========+=========+=========+ + +[*1] client logging not working +[*2] interlib logging not working +[*3] both client and interlib logging not working + +[*A] boils down to [*1], unless QB_LOG_INIT_DATA used on client side, + which then fails on + "non-empty implicit callsite section, otherwise target's linkage at + fault and logging would not work reliably" + assertion +[*B] boils down to [*1], unless QB_LOG_INIT_DATA used on interlib side, + which then fails on + "non-empty implicit callsite section, otherwise target's linkage at + fault and logging would not work reliably" + assertion +[*C] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side, + which then fails on + "non-empty implicit callsite section, otherwise target's linkage at + fault and logging would not work reliably" + assertion +[*E] boils down to [*1], unless QB_LOG_INIT_DATA used on client side, + which then fails on + "target's callsite section self-observable, otherwise target's + linkage at fault and logging would not work reliably" + assertion +[*F] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side, + which then fails on + "libqb's callsite section non-empty, otherwise libqb's linkage at + fault and logging would not work reliably" + assertion +[*G] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side, + which then fails on + "target's callsite section self-observable, otherwise target's linkage + at fault and logging would not work reliably" + assertion + +Note: the only problematic (i.e. not captured automatically by the +QB_LOG_INIT_DATA macro presumably utilized at every non-libqb logging +system participant in the form of a discrete compilation unit) +combination is the one intersecting at "BAD[*2]" pertaining "everything +but interlib compiled with ld.bfd < 2.29". It would, of course, be +solvable as well, but presumably not in an easy way, and that use case +should not be as frequent. + +Takeway: whenever your target (library or client program) actively +utilizes logging (meaning it emits at least a single log message), +YOU ARE strongly ENCOURAGED TO USE QB_LOG_INIT_DATA macro function +at (exactly) one of the source code files (presumably the main one) +per respective target's compilation unit. It will alleviate the +hassles possibly caused by downgrading libqb to the linker-vs-libqb +incompatibly compiled one or in similar circumstances arising merely +from the linker behaviour change, which the current build system/code +quake is all about. + +Signed-off-by: Jan Pokorný +--- + configure.ac | 1 + + include/qb/qblog.h | 67 ++++++++++++++++++++++++++++--- + lib/libqb.pc.in | 3 +- + tests/functional/log.am | 2 +- + tests/functional/log_external/Makefile.am | 8 +++- + 5 files changed, 72 insertions(+), 9 deletions(-) + +diff --git a/configure.ac b/configure.ac +index db7bc68..5601302 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -640,6 +640,7 @@ if test "x${GCC}" = xyes; then + AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1, + [Enabling code using __attribute__((section))]) + PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section" ++ AC_SUBST([client_dlopen_LIBS],[$dlopen_LIBS]) + fi + fi + +diff --git a/include/qb/qblog.h b/include/qb/qblog.h +index d38449d..e49c86c 100644 +--- a/include/qb/qblog.h ++++ b/include/qb/qblog.h +@@ -42,6 +42,11 @@ extern "C" { + #undef QB_HAVE_ATTRIBUTE_SECTION + #endif /* S_SPLINT_S */ + ++#ifdef QB_HAVE_ATTRIBUTE_SECTION ++#include ++#include ++#endif ++ + /** + * @file qblog.h + * The logging API provides four main parts (basics, filtering, threading & blackbox). +@@ -268,18 +273,70 @@ typedef void (*qb_log_filter_fn)(struct qb_log_callsite * cs); + extern struct qb_log_callsite QB_ATTR_SECTION_START[]; + extern struct qb_log_callsite QB_ATTR_SECTION_STOP[]; + +-/* optional on-demand self-check of (1) toolchain sanity and (2) non-void ++/* Related to the next macro, which is -- contrary to this -- public API */ ++#ifndef _GNU_SOURCE ++#warning "without _GNU_SOURCE defined (directly or not), QB_LOG_INIT_DATA cannot check libqb's own sanity" ++#define QB_NONAPI_LOG_INIT_DATA_EXTRA_ ++#else ++#define QB_NONAPI_LOG_INIT_DATA_EXTRA_ \ ++ /* libqb sanity (locating libqb by it's relatively unique \ ++ -- and currently only such per-linkage global one -- \ ++ non-functional symbol, due to possible confusion otherwise) */ \ ++ if (dladdr(dlsym(RTLD_DEFAULT, "facilitynames"), &work_dli) \ ++ && (work_handle = dlopen(work_dli.dli_fname, \ ++ RTLD_LOCAL|RTLD_LAZY)) != NULL) { \ ++ work_s1 = (struct qb_log_callsite *) \ ++ dlsym(work_handle, QB_ATTR_SECTION_START_STR); \ ++ assert(("libqb's callsite section not 1st in global resolution, \ ++otherwise target's linkage at fault and logging would not work reliably",\ ++ work_s2 != work_s1)); \ ++ work_s2 = (struct qb_log_callsite *) \ ++ dlsym(work_handle, QB_ATTR_SECTION_STOP_STR); \ ++ assert(("libqb's callsite section non-empty, otherwise libqb's \ ++linkage at fault and logging would not work reliably", \ ++ work_s1 != work_s2)); \ ++ dlclose(work_handle); } ++#endif ++ ++/** ++ * Optional on-demand self-check of (1) toolchain sanity and (2) non-void + * (implied by the justifying existence of at least a single logging callsite + * ~ qb_logt invocation) employment of logging subsystem in the target binary, + * which is presumably assured by it's author as of relying on this macro; + * only effective when link-time ("run-time amortizing") callsite collection +- * is available and may be extended in future for more in-depth self-validation ++ * is. ++ * ++ * Applying this macro in the target program/library is strongly recommended ++ * whenever the logging as framed by this header file is in use. Moreover, ++ * it's important to state that using this check while not ensuring _GNU_SOURCE ++ * macro definition is present at compile-time means only half of the available ++ * sanity checking will be performed, possibly resulting in libqb's own ++ * internally logged messages being lost. + */ + #define QB_LOG_INIT_DATA(name) \ + void name(void); \ +- void name(void) \ +- { assert(("non-empty callsite section", \ +- QB_ATTR_SECTION_START != QB_ATTR_SECTION_STOP)); } \ ++ void name(void) { \ ++ void *work_handle; struct qb_log_callsite *work_s1, *work_s2; \ ++ Dl_info work_dli; \ ++ /* our own (target's) sanity */ \ ++ if ((work_handle = dlopen(NULL, RTLD_LOCAL|RTLD_LAZY)) != NULL) { \ ++ work_s1 = (struct qb_log_callsite *) \ ++ dlsym(work_handle, QB_ATTR_SECTION_START_STR); \ ++ work_s2 = (struct qb_log_callsite *) \ ++ dlsym(work_handle, QB_ATTR_SECTION_STOP_STR); \ ++ assert(("target's callsite section self-observable, otherwise \ ++target's linkage at fault and logging would not work reliably", \ ++ work_s1 != NULL && work_s2 != NULL)); \ ++ work_s2 = (struct qb_log_callsite *) \ ++ dlsym(RTLD_DEFAULT, QB_ATTR_SECTION_START_STR); \ ++ assert(("target's callsite section 1st in global resolution, \ ++otherwise target's linkage at fault and logging would not work reliably",\ ++ work_s1 == work_s2)); } \ ++ QB_NONAPI_LOG_INIT_DATA_EXTRA_; \ ++ /* original "cherry on the cake" check, possibly expendable */ \ ++ assert(("non-empty implicit callsite section, otherwise target's \ ++linkage at fault and logging would not work reliably", \ ++ QB_ATTR_SECTION_START != QB_ATTR_SECTION_STOP)); } \ + void __attribute__ ((constructor)) name(void); + #else + #define QB_LOG_INIT_DATA(name) +diff --git a/lib/libqb.pc.in b/lib/libqb.pc.in +index 8a8d0ba..37d27b7 100644 +--- a/lib/libqb.pc.in ++++ b/lib/libqb.pc.in +@@ -7,5 +7,6 @@ Name: libqb + Version: @PACKAGE_VERSION@ + Description: libqb + Requires: +-Libs: -L${libdir} -lqb @LIBS@ ++Libs: -L${libdir} -lqb @client_dlopen_LIBS@ ++Libs.private: @LIBS@ + Cflags: -I${includedir} +diff --git a/tests/functional/log.am b/tests/functional/log.am +index 5fe1ae7..0753fa5 100644 +--- a/tests/functional/log.am ++++ b/tests/functional/log.am +@@ -20,7 +20,7 @@ + MAINTAINERCLEANFILES = Makefile.in + CLEANFILES = log_client.err.real log_interlib_client.err.real + +-AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include ++AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_builddir)/include -I$(top_srcdir)/include + + noinst_PROGRAMS = log_client log_interlib_client + # cannot use {check,noinst}_LTLIBRARIES because it leads to solely static lib +diff --git a/tests/functional/log_external/Makefile.am b/tests/functional/log_external/Makefile.am +index 36aa0af..ca1c8a5 100644 +--- a/tests/functional/log_external/Makefile.am ++++ b/tests/functional/log_external/Makefile.am +@@ -19,5 +19,9 @@ + + include ../log.am + +-log_client_LDFLAGS = -lqb +-liblog_inter_la_LIBADD = -lqb ++# while linking with system-wide version of libqb, we are still pursuing ++# local in-tree header file, hence we need to link with dynamic linking ++# library (which is a prerequisite for using QB_LOG_INIT_DATA defined ++# in qblog.h) explicitly ++log_client_LDFLAGS = -lqb @client_dlopen_LIBS@ ++liblog_inter_la_LIBADD = -lqb @client_dlopen_LIBS@ +-- +2.14.2 + diff --git a/05-High-bare-fix-for-libqb-logging-not-working-with-ld..patch b/05-High-bare-fix-for-libqb-logging-not-working-with-ld..patch new file mode 100644 index 0000000..ec6f018 --- /dev/null +++ b/05-High-bare-fix-for-libqb-logging-not-working-with-ld..patch @@ -0,0 +1,446 @@ +From a76c1d7c3466746c96dffd6406017d438bb22018 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= +Date: Fri, 6 Oct 2017 17:17:26 +0200 +Subject: [PATCH 5/6] High: bare fix for libqb logging not working with + ld.bfd/binutils 2.29+ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Initially with the help of the internal test suite and the failing log +test, it was eventually discovered[1] that these binutils commits going +to the recent 2.29 release affected the treatment of _start_SECNAME +and __stop_SECNAME symbols denoting the boundary start/stop addresses +of a SECNAME orphan section -- specifically in libqb context a custom +section (SECNAME=__verbose) used for link-time ("run-time amortizing") +callsite collection when there's a support in the toolchain[*]: + +https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=cbd0eecf261c2447781f8c89b0d955ee66fae7e9 +https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b27685f2016c510d03ac9a64f7b04ce8efcf95c4 +https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7dba9362c172f1073487536eb137feb2da30b0ff + +The first one explicitly states: +> Also __start_SECNAME and __stop_SECNAME symbols are marked as hidden +> by ELF linker so that __start_SECNAME and __stop_SECNAME symbols for +> section SECNAME in different modules are unique. + +The problem is that libqb silently depends on the previous status quo +ld.bfd linker behaviour of keeping those symbols externally visible, +which was apparently not granted as it has deliberately changed per +above. + +And then for 2.29.1 release of binutils once again, as someone actually +noticed something went overboard with the 2.29 changes: + +https://sourceware.org/bugzilla/show_bug.cgi?id=21964 +https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=487b6440dad57440939fab7afdd84a218b612796 + +At least that change doesn't invalidate all the effort being put into +the original version of the changeset, only the configure script check +had to be refined so as not to miss the "orphan section magic not +working properly out of the box, without a bandaid" obseration (see the +inline comment) -- the workaround arrangement needs to be applied in +that case as well. + +* * * + +So regarding the solution itself, the core of the fix was sketched at +the original Fedora targeted bug against binutils[2]. In short, we are +using a custom linker script that (re)describes the mentioned custom +orphan output section, or better yet, assuredly pushes that section, +and more importantly, it's own boundary denoting symbols, through into +the resulting binary when it's being linked (as in compile-time step). + +This solution alone, while working for the non-libqb (more on that +below) logging participants, is not good enough, as it requires all +libqb targets to start using new incantation (namely "-Wl,foo.t" switch) +in the final link step during compilation, which might be solvable +with a tweak in libqb's pkg-config file under assumption that practice +of using "pkg-config --libs libqb" is rigidly followed. Which is likely +a false expectation, and furthermore only for the regular consumption +model, as it doesn't cover the least bit the developmental one (refer +to previous-but-one "tests" commit message), e.g. applied for internal +examples + tests (but no local sub-checkout tree usage can be excluded). + +So further extensions were devised to cover both consumption models: + +- a. regular: + courtesy of binutils maintainer[3], we follow an idea to make libqb.so + (i.e. what the targets link against) rather a linker script on its + own, which first include the version-specified (e.g. libqb.so.0) file + into the link, then lists, in situ, the content of the linker script + per above, hence -lqb linking has the same effect as having both + "-lqb -Wl,foo.t" explicitly in the link command prior to this trick + +- b. developmental: + to eliminate any kind of race condition arising from the attempt + to post-modify libqb.la libtool archive file generated internally + by libtool, we sort of abuse "inherited_linker_flags" variable + within this file format, as it forms an accumulative value across + the whole transitive dependencies chain, which serves exactly our + purpose of injecting "-Wl,foo.t" switch equivalent for those + libtool-linking by L{D,IB}ADDing libqb.la; it's then enough to + craft a custom libtool archive file declaring that value, and + hook it into such dependency chain through libqb_la_LIBADD, and + with a little bit of further fiddling, it works as desired + (note that double occurrence of "-Wl,foo.t" equivalent achieved + at some point when developing this trick turned to be, surprisingly, + counter-productive) + +Last but not least, libqb itself needs to be linked with the mentioned +"-Wl,foo.t" equivalent for its own outgoing log messages to be honoured, +which is already achieved with the arrangement for b. above, and by +experiments, further redefinition of those boundary denoting symbols +as weak was necessary so as to make them truly global within libqb.so +proper (at least with binutils 2.29). + +* * * + +Finally, let's have a look how the already well-known test matrix +overview changes as of this commit, but first as a recap, +"X(Y)" denotes "X linked with linker Y": + X(a) .. ld.bfd < 2.29 + X(b) .. ld.bfd = 2.29 (and likely on) + +and here you are (values in denote non-trivial change +[not mere rewording] introduced as of this commit, in comparison to the +table stated in the preceding commit): + ++=========+=========+=========+=========+=========+=========+=========+ +#client(x)# libqb(a) usage # libqb(b) usage # +# vvv #---------+---------+---------+---------+---------+---------+ +# V # direct | libX(a) : libX(b) # direct | libX(a) : libX(b) # ++=========+=========+=========+=========+=========+=========+=========+ +# x = a # OK | OK : # | : # +# x = b # | : # | : # ++=========+=========+=========+=========+=========+=========+=========+ + +Everything is green \o/ + +Note: as of this fix, it is assumed that the non-green counterpart of +this table in the message for the preceding commit doubles as an +indicator how will mixing the logging participants wrt. linker+libqb +version work out, when "X(Y)" becomes read as "X linked with linker +Y under additional restriction on libqb version when compile-time link +is performed of the particular part": + X(a) .. ld.bfd < 2.29 OR [arbitrary ld.bfd AND libqb after this fix) + X(b) .. ld.bfd = 2.29 (and likely on) AND libqb up to, but excluding + this fix + +* * * + +Let's also state some imperfections and loops kept open: + +Deficiencies: +* whenever anything is compiled against our install-time-modified + libqb.so so as to force the visibility of the discussed symbols + (or when compiling [with] libqb internally): +> /usr/bin/ld: warning: ../lib/qblog_script.ld contains output sections; did you forget -T? + - not solvable as long as we use the linker script, and there's + hardly any other way not requiring the libqb consumers to adapt + in any way + +Open questions: +* what about binutils 2.99.1 partially mitigating the impact of the + above commits +* should we enable attribute((__section__)) for powerpc platforms? + it seems to work well there -- and related to that, we need to figure + out how static and dynamic call sites can live together -- say what + will happen to logging programs compiled with libqb w/o attribute + sections when the underlying libqb is flipped to the one with them... + +* * * + +[*] basically GCC's section("SECNAME") __attribute__ annotation of the +global variables + linker described behaviour previously mistakenly +taken for granted + +References: +[1] http://oss.clusterlabs.org/pipermail/developers/2017-July/000503.html +[2] https://bugzilla.redhat.com/show_bug.cgi?id=1477354#c2 + comment 8 +[3] https://bugzilla.redhat.com/show_bug.cgi?id=1477354#c9 + +Signed-off-by: Jan Pokorný +--- + configure.ac | 71 +++++++++++++++++++++++++++++++++++++++--------- + lib/Makefile.am | 67 +++++++++++++++++++++++++++++++++++++++++++++ + lib/log.c | 7 +++++ + lib/qblog_script.la.in | 15 ++++++++++ + lib/qblog_script.ld.in | 17 ++++++++++++ + lib/qblog_script_noop.ld | 1 + + 7 files changed, 165 insertions(+), 13 deletions(-) + create mode 100644 lib/qblog_script.la.in + create mode 100644 lib/qblog_script.ld.in + create mode 100644 lib/qblog_script_noop.ld + +diff --git a/configure.ac b/configure.ac +index 5601302..5d17443 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -618,31 +618,74 @@ AC_SUBST(HAVE_SLOW_TESTS) + + # --- callsite sections --- + if test "x${GCC}" = xyes; then ++ LDFLAGS_save="${LDFLAGS}" + AC_MSG_CHECKING([whether GCC supports __attribute__((section()) + ld supports orphan sections]) + if test "x${ac_cv_link_attribute_section}" = x ; then +- AC_TRY_RUN( +- AC_LANG_PROGRAM( ++ LDFLAGS="${LDFLAGS_save} -shared -fPIC" ++ AC_LINK_IFELSE( ++ [AC_LANG_SOURCE( + [[#include +- extern void * __start___verbose, * __stop___verbose;]], +- [[static int my_var __attribute__((section("__verbose"))) = 5; +- assert(("non-empty data section", __start___verbose != __stop___verbose)); +- assert(("no data section value loss", my_var == 5)); +- ]]), +- [gcc_has_attribute_section=yes], ++ extern int __start___verbose[], __stop___verbose[]; ++ int test(void) { ++ static int my_var __attribute__((section("__verbose"))) = 3; ++ assert(("L:non-empty data section", __start___verbose != __stop___verbose)); ++ assert(("L:no data section value loss", my_var == 3 /* for 2.29.1+ */)); ++ return *((int *) __start___verbose); ++ }]])], ++ [gcc_has_attribute_section=yes; cp "conftest${EXEEXT}" "lib_conftest.so"], + [gcc_has_attribute_section=no] + ) ++ LDFLAGS="${LDFLAGS_save}" + else + gcc_has_attribute_section=${ac_cv_link_attribute_section} + fi +- + AC_MSG_RESULT($gcc_has_attribute_section) +- if test $gcc_has_attribute_section = yes; then ++ ++ # in the failing case (e.g. with ld from binutils 2.29), it's likely the ++ # following will fail readily in linkage (hidden symbol `__stop___verbose' ++ # in conftest is referenced by DSO), but keep the sensible test (in-binary ++ # symbol is expected to be propagated into the library, and to draw the ++ # full circle back to binary through standard return value passing; ++ # -rpath passed because LD_LIBRARY_PATH exporting is unwieldy here); ++ # moreover, "my_var" == 3 assertion above is necessary so that binutils ++ # 2.29.1+ will not slip other parts of the overall is-workaround-needed ++ # harness, as it restored some (but not all) of the original behaviour, ++ # but the workaround is still provably needed ++ if test "x${gcc_has_attribute_section}" = xyes; then ++ AC_MSG_CHECKING([whether linker emits global boundary symbols for orphan sections]) ++ LDFLAGS="${LDFLAGS_save} -L. -l_conftest -Wl,-rpath=$(pwd)" ++ AC_TRY_RUN( ++ AC_LANG_PROGRAM( ++ [[#include ++ extern int __start___verbose[], __stop___verbose[]; ++ int test(void);]], ++ [[static int my_var __attribute__((section("__verbose"))) = 5; ++ assert(("P:non-empty data section", __start___verbose != __stop___verbose)); ++ assert(("P:no data section value loss", my_var == test() /*5?*/)); ++ ]]), ++ [gcc_has_attribute_section_visible=yes], ++ [gcc_has_attribute_section_visible=no] ++ ) ++ LDFLAGS="${LDFLAGS_save}" ++ AC_MSG_RESULT($gcc_has_attribute_section_visible) ++ rm -f "lib_conftest.so" ++ + AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1, + [Enabling code using __attribute__((section))]) +- PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section" + AC_SUBST([client_dlopen_LIBS],[$dlopen_LIBS]) ++ if test "x${gcc_has_attribute_section_visible}" = xyes; then ++ PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section" ++ else ++ AC_DEFINE([QB_NEED_ATTRIBUTE_SECTION_WORKAROUND], 1, ++ [Enabling code using __attribute__((section))]) ++ PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section-workaround" ++ fi + fi + fi ++AM_CONDITIONAL(HAVE_GCC_ATTRIBUTE_SECTION, [test "x${gcc_has_attribute_section}" = xyes]) ++AM_CONDITIONAL(NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND, ++ [test "x${gcc_has_attribute_section}" = xyes \ ++ && test "x${gcc_has_attribute_section_visible}" != xyes]) + + # --- ansi --- + if test "x${enable_ansi}" = xyes && \ +@@ -724,9 +767,11 @@ AC_CONFIG_FILES([Makefile + docs/Makefile + docs/common.dox + docs/html.dox +- docs/man.dox]) ++ docs/man.dox ++ lib/qblog_script.la:lib/qblog_script.la.in]) + +-AC_CONFIG_LINKS([tests/functional/GNUmakefile:tests/functional/GNUmakefile]) ++AC_CONFIG_LINKS([lib/qblog_script_noop.ld:lib/qblog_script_noop.ld ++ tests/functional/GNUmakefile:tests/functional/GNUmakefile]) + + AC_OUTPUT + +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 0bebeb5..cc7417c 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -19,6 +19,7 @@ + # along with libqb. If not, see . + + ++CLEANFILES = qblog_script.ld + MAINTAINERCLEANFILES = Makefile.in + + noinst_HEADERS = ipc_int.h util_int.h ringbuffer_int.h loop_int.h \ +@@ -39,9 +40,48 @@ source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c \ + log_syslog.c log_dcs.c log_format.c \ + map.c skiplist.c hashtable.c trie.c + ++# Following two files related to linkage using classic ld from binutils 2.29+ ++# with which we cannot afford to lose public access to section boundary symbols ++# (as the mentioned version started to scope them privately by default, see ++# the comment within the first of the files, ultimately leading to broken ++# logging functionality of libqb) deserve a bit of explanation: ++# * qblog_script.ld ++# - linker script that instructs the output section that those symbols should ++# be visible, i.e. supports the same behaviour regardless of ld version ++# - serves two purposes: ++# . local: libqb itself and its "private" (cf. examples) users need those ++# symbols visible, which is achieved with a help of the other file ++# . system-wide: whenever the non-private library users link against libqb ++# (it's development files), this linker script with ++# prepended INPUT command so as to refer to the actual ++# libqb library (it's numbered alias that is eventually ++# resolved to proper shared library) is masked as libqb.so, ++# this arrangement achieves the libqb's user will have ++# the discussed symbols visible alike ++# * qblog_script.la ++# - as mentioned earlier, this indirectly hooks into libtool machinery, with ++# the only true intention of injecting "-Wl," ++# into "inherited_linker_flags" libtool archive variable, from where it's ++# subsequently spread into the build process of all the internal library ++# users, assuming they have their dep arranged as "user_LIBADD=libqb.la" ++# (this also alleviates the burden on getting things right if, e.g., any ++# libqb user consumes it directly like this from its own sub-checkout tree) ++# - it indirectly, once libtool prechew the original link command ++# originally referring to this file, it turns such reference into the ++# "real" library reference (here combining libdir and old_library ++# variables within the file), also ensures libqb itself will visibly ++# expose the discussed symbols, because such references point again to ++# the (not enriched) linker script file that will get interpreted just ++# like that during the last build step of the library ++EXTRA_libqb_la_DEPENDENCIES = qblog_script.ld qblog_script.la ++EXTRA_DIST = qblog_script.ld.in qblog_script.la.in qblog_script_noop.ld ++ + libqb_la_SOURCES = $(source_to_lint) unix.c + libqb_la_CFLAGS = $(PTHREAD_CFLAGS) + libqb_la_LIBADD = $(LTLIBOBJS) $(dlopen_LIBS) $(PTHREAD_LIBS) $(socket_LIBS) ++if NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND ++libqb_la_LIBADD += qblog_script.la ++endif + + AM_LDFLAGS = $(LDFLAGS_COPY:-Bsymbolic-functions=) + +@@ -60,6 +100,33 @@ else + endif + endif + ++qblog_script.ld: %.ld: %.ld.in ++ $(AM_V_GEN)$(CPP) -xc -I$(top_srcdir)/include -C -P $< \ ++ | sed -n "/$$(sed -n '/^[^#]/{s/[*\/]/\\\0/g;p;q}' $<)/{:r;p;n;br}" \ ++ > $@ ++ ++# find the libqb.so symlink's target, if so, try to find out, iteratively, ++# its gradually shorter forms that likewise symlinks the same target as the ++# original libqb.so path, point to that file from the linker script using ++# qblog_script.ld as a template, storing result in place of original libqb.so ++# (e.g., libqb.so := "INPUT(libqb.so.0) " [...] "SECTIONS { " [...] "}") ++# NOTE: readlink nor realpath are POSIX; not chained links ready ++# NOTE: conservative check, i.e., not per NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND ++if HAVE_GCC_ATTRIBUTE_SECTION ++install-exec-hook: qblog_script.ld ++ target=$$(ls -l "$(DESTDIR)$(libdir)/libqb.so" || :); \ ++ target=$${target#* -> }; t1_bn=$$(basename "$${target}" || :); \ ++ while test -n "$${t1_bn}"; do t2_bn=$${t1_bn%.*[0-9]*}; \ ++ test "$${t2_bn}" != libqb.so || break; \ ++ test -L "$${t2_bn}" || { t1_bn=$${t2_bn}; continue; }; \ ++ t2_target=$$(ls -l "$${t2_bn}" || break); t2_target=$${t2_target#* -> }; \ ++ test "$${t2_target}" = "$${target}" || break; \ ++ t1_bn=$${t2_bn}; done; test -n "$${t1_bn}" || \ ++ { echo "only applicable to SO symlink scheme"; exit 1; }; \ ++ echo "INPUT($${t1_bn})" > "$(DESTDIR)$(libdir)/libqb.so-t" ++ cat $< >> "$(DESTDIR)$(libdir)/libqb.so-t" ++ mv -f "$(DESTDIR)$(libdir)/libqb.so-t" "$(DESTDIR)$(libdir)/libqb.so" ++endif + + pkgconfigdir = $(libdir)/pkgconfig + pkgconfig_DATA = libqb.pc +diff --git a/lib/log.c b/lib/log.c +index bfd218f..4ed432f 100644 +--- a/lib/log.c ++++ b/lib/log.c +@@ -40,6 +40,13 @@ + #include "util_int.h" + #include + ++#if defined(QB_NEED_ATTRIBUTE_SECTION_WORKAROUND) && !defined(S_SPLINT_S) ++/* following only needed to force these symbols be global ++ with ld 2.29: https://bugzilla.redhat.com/1477354 */ ++struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_START[] = { 0 }; ++struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_STOP[] = { 0 }; ++#endif ++ + static struct qb_log_target conf[QB_LOG_TARGET_MAX]; + static uint32_t conf_active_max = 0; + static int32_t in_logger = QB_FALSE; +diff --git a/lib/qblog_script.la.in b/lib/qblog_script.la.in +new file mode 100644 +index 0000000..f262df8 +--- /dev/null ++++ b/lib/qblog_script.la.in +@@ -0,0 +1,15 @@ ++# Generated by libtool ++# NOTE: above line is just to pass func_ltwrapper_script_p sanity check of ++# libtool script, as we are basically sort of abusing it so as to inject ++# our custom linker script to "private" (cf. examples) users of libqb.la ++ ++# shall rather carry a location of old_library (possibly libdir or something ++# else, but installed=no needed to suppress 'library moved' warning then) as ++# it's together (with libtool implied prefix otherwise) used for linking libqb ++libdir=@abs_builddir@ ++ ++# avoids issues with library_names (spurious rpath emitting, relink-on-install) ++old_library=qblog_script_noop.ld ++ ++# subject of our injection into libqb.la impacting build time for private users ++inherited_linker_flags=-Wl,@abs_builddir@/qblog_script.ld +diff --git a/lib/qblog_script.ld.in b/lib/qblog_script.ld.in +new file mode 100644 +index 0000000..1f37976 +--- /dev/null ++++ b/lib/qblog_script.ld.in +@@ -0,0 +1,17 @@ ++#include ++/* GNU ld script ++ This atypical arrangement enforces global visibility of boundary symbols ++ (QB_ATTR_SECTION_START, QB_ATTR_SECTION_STOP) for the custom section ++ QB_ATTR_SECTION used for compile-time offloading of the logging call sites ++ tracking. While libqb relies on these being global, default linker from ++ binutils change the visibility as of version 2.29, making the logging ++ unusable without artificial stimulus: https://bugzilla.redhat.com/1477354 */ ++SECTIONS { ++#ifdef QB_HAVE_ATTRIBUTE_SECTION ++ QB_ATTR_SECTION : { ++ QB_ATTR_SECTION_START = .; ++ *(QB_ATTR_SECTION); ++ QB_ATTR_SECTION_STOP = .; ++ } ++#endif ++} +diff --git a/lib/qblog_script_noop.ld b/lib/qblog_script_noop.ld +new file mode 100644 +index 0000000..f037fca +--- /dev/null ++++ b/lib/qblog_script_noop.ld +@@ -0,0 +1 @@ ++/* this is an empty linker script having a role of a NO-OP link object */ +-- +2.14.2 + diff --git a/06-Low-fix-internal-object-symbol-s-leak-expose-run-tim.patch b/06-Low-fix-internal-object-symbol-s-leak-expose-run-tim.patch new file mode 100644 index 0000000..4eb3f2d --- /dev/null +++ b/06-Low-fix-internal-object-symbol-s-leak-expose-run-tim.patch @@ -0,0 +1,152 @@ +From 1854db8ec1e3b246eff303b716495bafd90ded49 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= +Date: Fri, 6 Oct 2017 17:17:26 +0200 +Subject: [PATCH 6/6] Low: fix internal object symbol's leak & expose run-time + lib version +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The object in question has never been published through the header file, +hence it's presumably safe to make it static as it's meant to be. + +On the other hand, QB_LOG_INIT_DATA macro from qblog.h has already +started to depend on that symbol so as to locate the library handle +for libqb itself correctly. This is trivially fixed by finally exposing +library versioning info in run-time through objects identified by the +compile-time/static counterparts from qbconfig.h header file, with +lower-casing applied on originally upper-cased macro identifiers. +Better than to roll out a futile data object serving as an artificial +anchor for the above purpose, and this was a while due, afterall. + +Signed-off-by: Jan Pokorný +--- + include/qb/qbconfig.h.in | 5 ++++- + include/qb/qblog.h | 10 ++++++---- + include/qb/qbutil.h | 11 +++++++++++ + lib/log_format.c | 2 +- + lib/util.c | 7 +++++++ + tests/functional/log_client.c | 4 ++++ + tests/functional/log_client.err | 2 +- + 7 files changed, 34 insertions(+), 7 deletions(-) + +diff --git a/include/qb/qbconfig.h.in b/include/qb/qbconfig.h.in +index c1852e1..789fff3 100644 +--- a/include/qb/qbconfig.h.in ++++ b/include/qb/qbconfig.h.in +@@ -30,7 +30,10 @@ + /* Enabling code using __attribute__((section)) */ + #undef QB_HAVE_ATTRIBUTE_SECTION + +-/* versioning info: MAJOR, MINOR, MICRO, and REST components */ ++/* versioning info: MAJOR, MINOR, MICRO, and REST components; ++ note that static compile-time info is not that useful as run-time ++ querying the lower-cased symbolic constants directly from libqb ++ (see qbutil.h), but that was only introduced after v1.0.2 */ + #undef QB_VER_MAJOR + #undef QB_VER_MINOR + #undef QB_VER_MICRO +diff --git a/include/qb/qblog.h b/include/qb/qblog.h +index e49c86c..7ca236d 100644 +--- a/include/qb/qblog.h ++++ b/include/qb/qblog.h +@@ -279,10 +279,12 @@ extern struct qb_log_callsite QB_ATTR_SECTION_STOP[]; + #define QB_NONAPI_LOG_INIT_DATA_EXTRA_ + #else + #define QB_NONAPI_LOG_INIT_DATA_EXTRA_ \ +- /* libqb sanity (locating libqb by it's relatively unique \ +- -- and currently only such per-linkage global one -- \ +- non-functional symbol, due to possible confusion otherwise) */ \ +- if (dladdr(dlsym(RTLD_DEFAULT, "facilitynames"), &work_dli) \ ++ /* libqb sanity (locating libqb by it's relatively unique \ ++ non-functional symbol (the two are mutually exclusive, the \ ++ ordinarily latter was introduced by accident, the former is \ ++ intentional), due to possible confusion otherwise) */ \ ++ if ((dladdr(dlsym(RTLD_DEFAULT, "qb_ver_str"), &work_dli) \ ++ || dladdr(dlsym(RTLD_DEFAULT, "facilitynames"), &work_dli)) \ + && (work_handle = dlopen(work_dli.dli_fname, \ + RTLD_LOCAL|RTLD_LAZY)) != NULL) { \ + work_s1 = (struct qb_log_callsite *) \ +diff --git a/include/qb/qbutil.h b/include/qb/qbutil.h +index bfce349..a03bdf8 100644 +--- a/include/qb/qbutil.h ++++ b/include/qb/qbutil.h +@@ -289,6 +289,17 @@ uint64_t + qb_util_stopwatch_time_split_get(qb_util_stopwatch_t *sw, + uint32_t receint, uint32_t older); + ++/** Major component of the library version */ ++extern const uint8_t qb_ver_major; ++/** Minor component of the library version */ ++extern const uint8_t qb_ver_minor; ++/** Micro component of the library version */ ++extern const uint8_t qb_ver_micro; ++/** Rest (pertaining the mid-release-point) component of the library version */ ++extern const char *const qb_ver_rest; ++/** Complete library versioning info as a string */ ++extern const char *const qb_ver_str; ++ + /* *INDENT-OFF* */ + #ifdef __cplusplus + } +diff --git a/lib/log_format.c b/lib/log_format.c +index 712f447..e7e1f40 100644 +--- a/lib/log_format.c ++++ b/lib/log_format.c +@@ -49,7 +49,7 @@ static struct syslog_names prioritynames[] = { + {NULL, -1} + }; + +-struct syslog_names facilitynames[] = { ++static struct syslog_names facilitynames[] = { + {"auth", LOG_AUTH}, + #if defined(LOG_AUTHPRIV) + {"authpriv", LOG_AUTHPRIV}, +diff --git a/lib/util.c b/lib/util.c +index 6181a25..4693e58 100644 +--- a/lib/util.c ++++ b/lib/util.c +@@ -23,6 +23,7 @@ + #include "util_int.h" + #include + #include ++#include + #include + #include + +@@ -372,3 +373,9 @@ qb_util_stopwatch_time_split_get(qb_util_stopwatch_t *sw, + } + return (time_start - time_end) / QB_TIME_NS_IN_USEC; + } ++ ++const uint8_t qb_ver_major = QB_VER_MAJOR; ++const uint8_t qb_ver_minor = QB_VER_MINOR; ++const uint8_t qb_ver_micro = QB_VER_MICRO; ++const char *const qb_ver_rest = QB_VER_REST; ++const char *const qb_ver_str = QB_VER_STR; +diff --git a/tests/functional/log_client.c b/tests/functional/log_client.c +index aa6ebe1..3612dab 100644 +--- a/tests/functional/log_client.c ++++ b/tests/functional/log_client.c +@@ -53,6 +53,10 @@ main(int32_t argc, char *argv[]) + qb_log_tags_stringify_fn_set(my_tags_stringify); + qb_log_format_set(QB_LOG_STDERR, "[%5g|%p] %f:%l:%b"); + ++#if 0 ++ printf("\n==%s==\n\n", qb_ver_str); ++#endif ++ + #if 0 + printf("--\n"); + qb_log_callsites_dump(); +diff --git a/tests/functional/log_client.err b/tests/functional/log_client.err +index 0ae7665..c9c955c 100644 +--- a/tests/functional/log_client.err ++++ b/tests/functional/log_client.err +@@ -1,2 +1,2 @@ +-[MAIN |debug] ../log_client.c:63:hello ++[MAIN |debug] ../log_client.c:67:hello + [libqb|error] log_blackbox.c:196:qb_log_blackbox_print_from_file: No such file or directory (2) +-- +2.14.2 + diff --git a/libqb.spec b/libqb.spec index 7ad538e..71469a5 100644 --- a/libqb.spec +++ b/libqb.spec @@ -2,15 +2,19 @@ Name: libqb Version: 1.0.2 -Release: 7%{?dist} +Release: 8%{?dist} Summary: An IPC library for high performance servers Group: System Environment/Libraries License: LGPLv2+ URL: https://github.com/ClusterLabs/libqb Source0: https://github.com/ClusterLabs/libqb/releases/download/v%{version}/%{name}-%{version}.tar.xz -Patch0: 0001-build-configure-run-attribute-section-test-through-r.patch -Patch1: 0002-WIP-5-Experimental-fix-for-libqb-logging-not-working.patch +Patch0: 01-Med-qblog.h-better-explanation-behaviour-of-QB_LOG_I.patch +Patch1: 02-build-configure-run-attribute-section-test-through-r.patch +Patch2: 03-tests-new-sort-of-tests-dubbed-functional-cover-link.patch +Patch3: 04-Med-add-extra-run-time-client-side-sanity-check-that.patch +Patch4: 05-High-bare-fix-for-libqb-logging-not-working-with-ld..patch +Patch5: 06-Low-fix-internal-object-symbol-s-leak-expose-run-tim.patch BuildRequires: autoconf automake libtool doxygen procps check-devel # https://fedoraproject.org/wiki/Packaging:C_and_C%2B%2B#BuildRequires_and_Requires @@ -36,7 +40,8 @@ make %{?_smp_mflags} V=1 %if 0%{?with_check} %check -make -j1 check +make V=1 check \ + && make -C tests/functional/log_internal V=1 check %endif %install @@ -72,6 +77,10 @@ developing applications that use %{name}. %{_mandir}/man3/qb*3* %changelog +* Fri Oct 06 2017 Jan Pokorný - 1.0.2-8 +- Evolution of the previous (rhbz#1478089, rhbz#1487787) +- New test included in check phase (as per upsteam) + * Mon Sep 04 2017 Jan Pokorný - 1.0.2-7 - Evolution of the previous (rhbz#1478089, rhbz#1487787)