1.0.2-8 - Evolution of the previous (rhbz#1478089, rhbz#1487787)

- New test included in check phase (as per upsteam)

Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
This commit is contained in:
Jan Pokorný 2017-10-06 17:36:34 +02:00
parent b5b22505a5
commit b933a4c6ac
No known key found for this signature in database
GPG Key ID: 61BBB23A9E8F8DE2
8 changed files with 1919 additions and 356 deletions

View File

@ -1,336 +0,0 @@
From 10cd5db8821e4d313ae5245b33061e02ba8d3ff5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
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ý <jpokorny@redhat.com>
---
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 <assert.h>
+ 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 <assert.h>
- 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 <http://www.gnu.org/licenses/>.
+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,<path to qblog_script.ld>"
+# 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 <regex.h>
+#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 <qb/qblog.h>
+/* 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

View File

@ -0,0 +1,66 @@
From 8bfe49d79c1b7ae1aa4b7b22b627afa40a4a08d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
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ý <jpokorny@redhat.com>
---
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

View File

@ -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?= <jpokorny@redhat.com>
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ý <jpokorny@redhat.com>
---
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 <assert.h>
- 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 <assert.h>
+ 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

View File

@ -0,0 +1,964 @@
From d9ed1dbcd9d58cac8573b75e6db323757f39e27b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
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ý <jpokorny@redhat.com>
---
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 <jpokorny@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+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 <jpokorny@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+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 <jpokorny@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#include "os_base.h"
+#include <qb/qblog.h>
+
+#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 <jpokorny@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+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 <jpokorny@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#include "os_base.h"
+#include <qb/qblog.h>
+
+#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 <jpokorny@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#include "os_base.h"
+#include <qb/qblog.h>
+
+#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 <jpokorny@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+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 <jpokorny@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+./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 <jpokorny@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+./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 <jpokorny@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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] <libqb.src.rpm> | 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/<timestamp>_<input_name>[_<tag>]'" \
+ || do_proceed "$@"
--
2.14.2

View File

@ -0,0 +1,257 @@
From 82835b453ac212937592c5a47e992d70b6f2d82b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
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 <angle brackets> 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] #<BAD[*E]>|<BAD[*F]>:<BAD[*G]>#
# x = b # BAD[*A] | BAD[*B] : BAD[*C] #<BAD[*E]>|<BAD[*F]>:<BAD[*G]>#
+=========+=========+=========+=========+=========+=========+=========+
[*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ý <jpokorny@redhat.com>
---
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 <assert.h>
+#include <dlfcn.h>
+#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

View File

@ -0,0 +1,446 @@
From a76c1d7c3466746c96dffd6406017d438bb22018 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
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 <angle brackets> 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 : <OK> # <OK> | <OK> : <OK> #
# x = b # <OK> | <OK> : <OK> # <OK> | <OK> : <OK> #
+=========+=========+=========+=========+=========+=========+=========+
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ý <jpokorny@redhat.com>
---
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 <assert.h>
- 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 <assert.h>
+ 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 <http://www.gnu.org/licenses/>.
+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,<path to qblog_script.ld>"
+# 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 <regex.h>
+#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 <qb/qblog.h>
+/* 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

View File

@ -0,0 +1,152 @@
From 1854db8ec1e3b246eff303b716495bafd90ded49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
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ý <jpokorny@redhat.com>
---
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 <pthread.h>
#include <sys/stat.h>
+#include <qb/qbconfig.h>
#include <qb/qbdefs.h>
#include <qb/qbutil.h>
@@ -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

View File

@ -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ý <jpokorny+rpm-libqb@redhat.com> - 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ý <jpokorny+rpm-libqb@redhat.com> - 1.0.2-7
- Evolution of the previous (rhbz#1478089, rhbz#1487787)