Skip to content

Commit

Permalink
High: bare fix for libqb logging not working with ld.bfd/binutils 2.29+
Browse files Browse the repository at this point in the history
(or rather [read on]: "bare" fix, now that we established means to
analyse the impact of the linker-dependent misbehaviour and to detect
some of its symptoms in preceding two commits, respectively)

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:

http://lists.gnu.org/archive/html/bug-binutils/2017-08/msg00195.html
(overview of the original bug discussion, rather than directly
https://sourceware.org/bugzilla/show_bug.cgi?id=21964, which is
a result of a conflct resolution when restoring bugzilla backup)
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 band aid" observation
(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 executable 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 (if not impaired per the
  note below), fitting exactly our purpose of injecting "-Wl,foo.t"
  switch equivalent for those libtool-linking by L{D,IB}ADD'ing
  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
  present at some stages of sorting this trick turned out to be,
  surprisingly, counter-productive, which should now demistify the
  very existence of effectively empty qblog_script_noop.ld file);

  NOTE: some forms of libtool distribution (debian + derivatives ones
  in particular) undermine natural transitive dependency propagation
  with a deliberate cut off (https://bugs.debian.org/702737), so we
  need to ensure the "impairment" is not happening by force (corosync
  precedent: corosync/corosync@0f1dc5c1)
  ^ something like this needs to be applied for any such "private
    consumer" (although it hopefully goes without saying this way
    of consuming libqb outside of it's own playground is hardly
    the Right Thing) if portability is important, nonetheless!

* * *

On the address of linker script workaround, there are linkers out there
that do not support the trick, for instance:
- ld.gold from binutils (but it has hardly ever been working with
  orphan sections, anyway:
  https://sourceware.org/bugzilla/show_bug.cgi?id=22291)
- ancient versions of ld.bfd, e.g. 10+ years old one used as a native
  system linker even in the most recent releases of FreeBSD, unless
  GCC toolchain is used instead
If these are hit when (because) the compiler has already demonstrated it
supports "section" attribute, the build system configuration is forcibly
stopped, simply to stay conceptually compatible with the prior state in
which the affinity to leverage that feature hasn't been called off
under any circumstances.  One is, however, able to achieve exactly
this behaviour with --enable-nosection-fallback switch, but if some
other participants in the logging, possibly linked with a more friendly
linker, do utilize this orphan section, logging may silently break
(another reason to require an explicit sign-off).

Another note, the particular self-check change slightly touched in the
previous commit but otherwise predating this whole effort by far needs
to be modified now once again, this time because linker-script-based
workaround for newer linkers as stated causes the section boundary
symbols to be present regardless if that section is utilized, leading
to a self-inflicted breakage due to these empty section symbols suddenly
winning in the symbol resolution mechanism (previously the empty section
would be dropped incl. the boundary symbols), causing problems down the
line.  It also makes this very check self-contained in the same
compilation unit that trigggers it, whereas previously it used to be the
said "arbitrary" winner and things kept silently working just because
failure condition -- empty section -- would be implicitly isolated.

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
under all circumstances, 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).

* * *

To provide a high-level prioritized overview of what drove the approach:

- PRESERVATION OF BINARY COMPATIBILITY (ABI), which is achieved except
  for a single "ABI nongracefulness" I am aware of but that's more
  a consequence of slightly incorrect assumptions in the logic of
  QB_LOG_INIT_DATA macro function predating this whole affair by
  a long shot and which the patchset finally rectifies:

  if in the run-time dynamic link, following is combined:
  (. libqb, arbitrary variant: pre-/post-fix, binutils < / >= 2.29)
  . an "intermediate" library (something that the end executable links
    with) triggering QB_LOG_INIT_DATA macro and being built with
    pre-fix libqb (and perhaps only with binutils < 2.29)
  . end executable using no libqb's logging at all, but being built
    with post-fix libqb (and arbitrary binutils < / >= 2.29)
  then, unlike when executable is built with pre-fix libqb, the
  special callsite data containing section in the ELF structure
  of the executable is created + its boundary denoting symbols
  defined within, despite the section being empty (did not happen
  with pre-fix libqb), and because the symbols defined within the
  target program have priority over that of shared libraries in the
  symbol resolution fallback scheme, the assertion of QB_LOG_INIT_DATA
  of the mentioned intermediate library will actually be evaluating
  the inequality of boundaries for the section of the executable(!)
  rather than it's own (or whatever higher prio symbols are hit,
  presumably only present if the section at that level is non-empty,
  basically a generalization of the story so far);

  the problem then manifests as unability to run said executable
  as it will fail because of the intermediate library inflicted
  assertion (sadly with very unhelpful "Assertion `0' failed"
  message);

  fortunately, there's enough flexibility so as how to fix
  this, either should be fine:
  . have everything in the executable's library dependency closure
    that links against libqb assurably (compile-time) linked with one
    variant of libqb only (either all pre-fix or post-fix, mind the
    apparent limitation of binutils' versions with the former)
  . have the end executable (that does not use logging at all as
    discussed precondition) linked using substitution like this:
    s/-lqb/-l:libqb.so.0/  (you may need to adapt the number later)
    and you may also need to add this CPPFLAG for the executable:
    -DQB_KILL_ATTRIBUTE_SECTION

- as high level of isolation of the client space from the linker
  (respectively toolchain) subtleties as possible (no new compilation
  flags and such required, plus there's no way to hook any dynamic
  computational ad-hoc decision when the compilation is about to
  happen, anyway), and in turn, versatility is preserved as much as
  possible

* * *

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 (+ 2.29.1 and hopefully 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 (loosely though[!],
as the occurrence of empty callsite section can no longer be attributed
to something bad going on as of this fix that enforces its presence
unconditionally, whereas it would be suppressed when unused before
with kind linkers, hence some other conditions can be witnessed
especially when QB_LOG_INIT_DATA misused in no-logging context)
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 aspect
* as already mentioned, lacking compatibility with ld.gold linker and
  won't foreseeably be (cf. https://bugzilla.redhat.com/1500898#c7)
  - please stick with ld.bfd (i.e. default ld linker), which you
    had to do in the past anyway (at least for compiling libqb
    itself)

Open questions:
* should we enable attribute((__section__)) for powerpc and other minor
  platforms if the feature is proved to be working there as well?
  and if/when that's going to happen, we need to figure out the
  transition plan to be spread throughout an extended period to keep
  the transition smooth -- notably when now-with-callsite-section
  clients will get run-time linked with callsite-section-not-a-default
  libqb (say upon it's downgrade), and for that, the libqb's support
  alone should be enabled year(s) ahead of the actual client space...

* * *

[*] 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ý <[email protected]>
  • Loading branch information
jnpkrn committed Dec 12, 2017
1 parent cdb0269 commit 20246f5
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 29 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ aclocal.m4
autom4te.cache/
config.status
configure
conftest.*
.libs

# since we use subdir-objects as automake option
Expand All @@ -28,6 +29,9 @@ configure
/.tarball-version
/tag-*

/lib/qblog_script.ld
# already captured with wildcard: /lib/qblog_script.la

libtool
.version
libqb.spec
Expand Down
2 changes: 2 additions & 0 deletions check
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ check_nosection() {
echo "checking nosection"
echo "======================="
# no __attribute__((section))
# NOTE: alternatively CPPFLAGS=-DQB_KILL_ATTRIBUTE_SECTION, but
# that won't shortcut many initial/configure decisions
check "ac_cv_link_attribute_section=no"
}

Expand Down
156 changes: 138 additions & 18 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ AM_CONDITIONAL(HAVE_DOXYGEN, test -n "${DOXYGEN}")
AC_CHECK_PROGS([SPLINT], [splint])
AM_CONDITIONAL(HAVE_SPLINT, test -n "${SPLINT}")
AC_CHECK_TOOLS([NM], [eu-nm nm], [:])
AC_CHECK_TOOLS([READELF], [eu-readelf readelf], [:])
AM_PATH_PYTHON([2.6],, [:])
AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :])

Expand Down Expand Up @@ -504,6 +505,14 @@ AC_ARG_ENABLE([debug],
AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage],[coverage analysis of the codebase])])

AC_ARG_ENABLE([interlib-deps],
[AS_HELP_STRING([--disable-interlib-deps],
[disable inter-library dependencies (might break builds)])])

AC_ARG_ENABLE([nosection-fallback],
[AS_HELP_STRING([--enable-nosection-fallback],
[allow (logging compat-breaking?) fallback when orphan section dead-ended])])

AC_ARG_ENABLE([slow-tests],
[AS_HELP_STRING([--enable-slow-tests],[build and run slow tests])])

Expand Down Expand Up @@ -612,6 +621,19 @@ else
COVERAGE_LDFLAGS=""
fi

# --- inter-library dependencies ---
# because of debian/ubuntu swimming against the stream
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=702737,
# override the libtool variable by force because the current
# arrangement relies on transitive dependency propagation
AC_MSG_NOTICE([Enabling inter-library dependencies: $enable_interlib_deps])
if test "x${enable_interlib_deps}" = xno; then
link_all_deplibs=no
else
link_all_deplibs=yes
fi

# --- slow tests ---
if test "x${enable_slow_tests}" = xyes ; then
AC_DEFINE([HAVE_SLOW_TESTS], 1,[have slow tests])
AC_MSG_NOTICE([Enabling Slow tests])
Expand All @@ -621,20 +643,60 @@ AC_SUBST(HAVE_SLOW_TESTS)

# --- callsite sections ---
if test "x${GCC}" = xyes; then
AX_SAVE_FLAGS
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" # we are compiling shared lib
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;
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${ac_exeext}" "conftest.so"],
[gcc_has_attribute_section=no]
)
AX_RESTORE_FLAGS
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 likely the
# following will fail readily in linkage (hidden symbol `__stop___verbose'
# in conftest is referenced by DSO), but keep the sensible test
# (in-executable symbol is expected to be propagated into the library,
# and to draw the full circle back to the executable through standard
# return value passing (respectively no-exec probing to spot the issue);
# -rpath passed because LD_LIBRARY_PATH exporting is unwieldy here);
# moreover, "my_var" == 3 assertion above (respectively checking if the
# boundary symbol visibility differs from DEFAULT in readelf output) 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])
LIBS="${LIBS} -L. -l:conftest${shrext_cmds} -Wl,-rpath=$(pwd)"
dnl could be turned to AC_TRY_RUN (first assertion is equivalent to
dnl the further check in action-if-true), but that would prevent
dnl cross-building
AC_LINK_IFELSE(
[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;
assert("non-empty data section"
assert("E:non-empty data section"
&& __start___verbose != __stop___verbose);
assert("no data section value loss"
&& my_var == 5);]]
assert("E:no data section value loss"
&& my_var == test() /*5?*/);]]
)],
[# alternatively something like (but requires number parsing):
# readelf -SW "conftest${ac_exeext}" \
Expand All @@ -644,22 +706,78 @@ if test "x${GCC}" = xyes; then
verbose_stop_addr=$(${NM} -g --portability -- "conftest${ac_exeext}" \
| grep __stop___verbose | cut -d" " -f 3)
test "${verbose_start_addr}" = "${verbose_stop_addr}" \
&& gcc_has_attribute_section=no \
|| gcc_has_attribute_section=yes],
[gcc_has_attribute_section=no]
&& gcc_has_attribute_section_visible=no \
|| { verbose_start_type=$(${READELF} -s backup \
| sed -n '/__start___verbose/{s/^\s*//p;q}' \
| tr -s ' ' \
| cut -d" " -f6)
test "${verbose_start_type}" = DEFAULT \
&& gcc_has_attribute_section_visible=yes \
|| gcc_has_attribute_section_visible=no; }],
[gcc_has_attribute_section_visible=no]
)
else
gcc_has_attribute_section=${ac_cv_link_attribute_section}
fi
AX_RESTORE_FLAGS
AC_MSG_RESULT($gcc_has_attribute_section_visible)
rm -f "conftest${shrext_cmds}"

if test "x${gcc_has_attribute_section_visible}" = xno; then
# check if the linker script based workaround is
# feasible at all, otherwise fallback to using no
# section attribute while making some noise about it
# as combining with-without accustomed logging
# participants is currently uncharted waters
AC_MSG_CHECKING([whether linker workaround for orphan sections usable])
>conftest.ld cat <<-EOF
SECTIONS {
__verbose : {
__start___verbose = .;
*(__verbose);
__stop___verbose = .;
}
}
EOF
LDFLAGS="${LDFLAGS} -Wl,conftest.ld"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <assert.h>
extern int __start___verbose[], __stop___verbose[];
int test(void);]],
[[static int my_var __attribute__((section("__verbose"))) = 5;
assert("E:non-empty data section"
&& __start___verbose != __stop___verbose);
assert("E:no data section value loss"
&& my_var == 5);]]
)],
[],
[gcc_has_attribute_section=no]
)
AX_RESTORE_FLAGS
AC_MSG_RESULT([$gcc_has_attribute_section])
rm -f "conftest.ld"
fi

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"
AC_SUBST([client_dlopen_LIBS],[$dlopen_LIBS])
if test "x${gcc_has_attribute_section}" = xyes; then
AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1,
[Enabling code using __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
elif test "x${enable_nosection_fallback}" = xyes; then
AC_MSG_NOTICE([Falling back to not using orphan section])
else
AC_MSG_ERROR([Would use section attribute, cannot; see --enable-nosection-fallback])
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 && \
Expand Down Expand Up @@ -741,9 +859,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

Expand Down
32 changes: 26 additions & 6 deletions include/qb/qblog.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ extern "C" {
* scope in exactly one source file (preferably the main one) to be mixed into
* the resulting compilation unit. This is a self-defensive measure for when
* the linker-assisted collection of callsite data silently fails, which could
* otherwise go unnoticed, causing troubles down the road.
* otherwise go unnoticed, causing troubles down the road, but alas it cannot
* discern misuse of @c QB_LOG_INIT_DATA() macro in no-logging context from
* broken callsite section handling assumptions owing to overboard fancy
* linker -- situation that the self-check aims to detect in the first place.
*
* @par Configuring log targets.
* A log target can be syslog, stderr, the blackbox, stdout, or a text file.
Expand Down Expand Up @@ -287,12 +290,13 @@ extern struct qb_log_callsite QB_ATTR_SECTION_STOP[];

/* Related to the next macro that is -- unlike this one -- a public API */
#ifndef _GNU_SOURCE
#define QB_NONAPI_LOG_INIT_DATA_EXTRA_ \
#define QB_NONAPI_LOG_INIT_DATA_EXTRA_(name) \
_Pragma(QB_PP_STRINGIFY(GCC warning QB_PP_STRINGIFY( \
without "_GNU_SOURCE" defined (directly or not) \
QB_LOG_INIT_DATA cannot check sanity of libqb proper)))
QB_LOG_INIT_DATA cannot check sanity of libqb proper \
nor of the target site originating this check alone)))
#else
#define QB_NONAPI_LOG_INIT_DATA_EXTRA_ \
#define QB_NONAPI_LOG_INIT_DATA_EXTRA_(name) \
{ Dl_info work_dli; \
/* libqb sanity (locating libqb by it's relatively unique \
-- and currently only such per-linkage global one -- \
Expand All @@ -310,6 +314,23 @@ libqb's build is at fault, preventing reliable logging" \
assert("libqb's callsite section is populated, otherwise \
libqb's build is at fault, preventing reliable logging" \
&& work_s1 != work_s2); \
dlclose(work_handle); } \
/* sanity of the target site originating this check alone */ \
if (dladdr(dlsym(RTLD_DEFAULT, QB_PP_STRINGIFY(name)), &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); \
work_s2 = (struct qb_log_callsite *) \
dlsym(work_handle, QB_ATTR_SECTION_STOP_STR); \
assert("target's own callsite section observable, otherwise \
target's own linkage at fault and logging would not work reliably \
(unless QB_LOG_INIT_DATA macro used unexpectedly in no-logging context)"\
&& work_s1 != NULL && work_s2 != NULL); \
assert("target's own callsite section non-empty, otherwise \
target's own linkage at fault and logging would not work reliably \
(unless QB_LOG_INIT_DATA macro used unexpectedly in no-logging context)"\
&& work_s1 != work_s2); \
dlclose(work_handle); } }
#endif /* _GNU_SOURCE */

Expand Down Expand Up @@ -354,8 +375,7 @@ libqb's build is at fault, preventing reliable logging" \
target's and/or libqb's build is at fault, preventing reliable logging" \
&& work_s1 != NULL && work_s2 != NULL); \
dlclose(work_handle); /* perhaps overly eager thing to do */ } \
/* better targeted attestations when available */ \
QB_NONAPI_LOG_INIT_DATA_EXTRA_; \
QB_NONAPI_LOG_INIT_DATA_EXTRA_(name); \
/* finally, original, straightforward check */ \
assert("implicit callsite section is populated, otherwise \
target's build is at fault, preventing reliable logging" \
Expand Down
Loading

0 comments on commit 20246f5

Please sign in to comment.