This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH 3/3] libctf: look for a qsort_r that functions properly
- From: Nick Alcock <nick dot alcock at oracle dot com>
- To: binutils at sourceware dot org
- Cc: jose dot marchesi at oracle dot com, John dot W dot Marshall at glasgow dot ac dot uk, sebastian dot huber at embedded-brains dot de
- Date: Mon, 3 Jun 2019 21:47:35 +0100
- Subject: [PATCH 3/3] libctf: look for a qsort_r that functions properly
- References: <20190603204735.203510-1-nick.alcock@oracle.com>
We cannot just look for any declaration of qsort_r, because some
operating systems have a qsort_r that has a different prototype
but which still has a pair of pointers in the right places (the last two
args are interchanged), so we cannot rely on compilation errors to flag
up a problem.
So, instead, use AC_RUN_IFELSE to check for the function of qsort_r(),
passing function pointers in to both args and making sure that we never
actually dereference the arg pointer.
This may still be problematic on systems with different representations
for function pointers and integer pointers, but even then we should get
the right result from configure (there just might be an ugly coredump
too).
(Now we are not using AC_LIBOBJ any more, we can use a better name for
the qsort_r replacement as well.)
libctf/
* qsort_r.c: Rename to...
* ctf-qsort_r.c: ... this.
(_quicksort): Define to ctf_qsort_r.
* ctf-decls.h (qsort_r): Remove.
(ctf_qsort_r): Add.
* Makefile.am (libctf_a_LIBADD): Remove.
(libctf_a_SOURCES): New, add ctf-qsort_r.c.
* ctf-archive.c (ctf_arc_write): Call ctf_qsort_r, not qsort_r.
* ctf-create.c (ctf_update): Likewise.
* configure.ac: Check for specific qsort_r that functions properly,
not just for any declaration of it.
* Makefile.in: Regenerate.
* config.h.in: Likewise.
* configure: Likewise.
---
libctf/Makefile.am | 4 +-
libctf/Makefile.in | 29 ++++---
libctf/config.h.in | 7 +-
libctf/configure | 115 +++++++++++++++-------------
libctf/configure.ac | 30 +++++++-
libctf/ctf-archive.c | 9 ++-
libctf/ctf-create.c | 2 +-
libctf/ctf-decls.h | 16 +++-
libctf/{qsort_r.c => ctf-qsort_r.c} | 2 +-
9 files changed, 134 insertions(+), 80 deletions(-)
rename libctf/{qsort_r.c => ctf-qsort_r.c} (99%)
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index 49c9f5280a..926c9919c5 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -35,4 +35,6 @@ noinst_LIBRARIES = libctf.a
libctf_a_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c ctf-decl.c ctf-error.c \
ctf-hash.c ctf-labels.c ctf-lookup.c ctf-open.c ctf-open-bfd.c \
ctf-subr.c ctf-types.c ctf-util.c
-libctf_a_LIBADD = $(LIBOBJS)
+if NEED_CTF_QSORT_R
+libctf_a_SOURCES += ctf-qsort_r.c
+endif
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index c2cada6616..4fea156c44 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -104,6 +104,7 @@ POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
+@NEED_CTF_QSORT_R_TRUE@am__append_1 = ctf-qsort_r.c
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
@@ -128,12 +129,17 @@ am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
am__v_AR_0 = @echo " AR " $@;
am__v_AR_1 =
libctf_a_AR = $(AR) $(ARFLAGS)
-libctf_a_DEPENDENCIES = $(LIBOBJS)
+libctf_a_LIBADD =
+am__libctf_a_SOURCES_DIST = ctf-archive.c ctf-dump.c ctf-create.c \
+ ctf-decl.c ctf-error.c ctf-hash.c ctf-labels.c ctf-lookup.c \
+ ctf-open.c ctf-open-bfd.c ctf-subr.c ctf-types.c ctf-util.c \
+ ctf-qsort_r.c
+@NEED_CTF_QSORT_R_TRUE@am__objects_1 = ctf-qsort_r.$(OBJEXT)
am_libctf_a_OBJECTS = ctf-archive.$(OBJEXT) ctf-dump.$(OBJEXT) \
ctf-create.$(OBJEXT) ctf-decl.$(OBJEXT) ctf-error.$(OBJEXT) \
ctf-hash.$(OBJEXT) ctf-labels.$(OBJEXT) ctf-lookup.$(OBJEXT) \
ctf-open.$(OBJEXT) ctf-open-bfd.$(OBJEXT) ctf-subr.$(OBJEXT) \
- ctf-types.$(OBJEXT) ctf-util.$(OBJEXT)
+ ctf-types.$(OBJEXT) ctf-util.$(OBJEXT) $(am__objects_1)
libctf_a_OBJECTS = $(am_libctf_a_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -164,7 +170,7 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libctf_a_SOURCES)
-DIST_SOURCES = $(libctf_a_SOURCES)
+DIST_SOURCES = $(am__libctf_a_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -196,7 +202,7 @@ am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(top_srcdir)/../ar-lib $(top_srcdir)/../compile \
$(top_srcdir)/../depcomp $(top_srcdir)/../install-sh \
$(top_srcdir)/../missing $(top_srcdir)/../mkinstalldirs \
- ChangeLog qsort_r.c
+ ChangeLog
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
@@ -323,11 +329,10 @@ ZLIBINC = @zlibinc@
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir) -I$(top_srcdir)/../include -I$(top_srcdir)/../bfd -I../bfd
AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@ $(ZLIBINC)
noinst_LIBRARIES = libctf.a
-libctf_a_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c ctf-decl.c ctf-error.c \
- ctf-hash.c ctf-labels.c ctf-lookup.c ctf-open.c ctf-open-bfd.c \
- ctf-subr.c ctf-types.c ctf-util.c
-
-libctf_a_LIBADD = $(LIBOBJS)
+libctf_a_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c ctf-decl.c \
+ ctf-error.c ctf-hash.c ctf-labels.c ctf-lookup.c ctf-open.c \
+ ctf-open-bfd.c ctf-subr.c ctf-types.c ctf-util.c \
+ $(am__append_1)
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -396,7 +401,6 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
-@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/qsort_r.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-archive.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-create.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-decl.Po@am__quote@
@@ -407,6 +411,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-lookup.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-open-bfd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-open.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-qsort_r.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-subr.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-types.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-util.Po@am__quote@
@@ -687,7 +692,7 @@ clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
- -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
@@ -735,7 +740,7 @@ installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
- -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/libctf/config.h.in b/libctf/config.h.in
index 0ecb5bb721..dff5501609 100644
--- a/libctf/config.h.in
+++ b/libctf/config.h.in
@@ -9,10 +9,6 @@
/* Define to 1 if you have the <byteswap.h> header file. */
#undef HAVE_BYTESWAP_H
-/* Define to 1 if you have the declaration of `qsort_r', and to 0 if you
- don't. */
-#undef HAVE_DECL_QSORT_R
-
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
@@ -31,6 +27,9 @@
/* Define to 1 if you have the `pread' function. */
#undef HAVE_PREAD
+/* Whether a qsort_r exists with a void *arg as its last arg. */
+#undef HAVE_QSORT_R_ARG_LAST
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
diff --git a/libctf/configure b/libctf/configure
index 4fb44eb2cc..c59e4c6abc 100755
--- a/libctf/configure
+++ b/libctf/configure
@@ -624,6 +624,8 @@ ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
+NEED_CTF_QSORT_R_FALSE
+NEED_CTF_QSORT_R_TRUE
zlibinc
zlibdir
ac_libctf_warn_cflags
@@ -1809,52 +1811,6 @@ $as_echo "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_func
-
-# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
-# ---------------------------------------------
-# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
-# accordingly.
-ac_fn_c_check_decl ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- as_decl_name=`echo $2|sed 's/ *(.*//'`
- as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
-$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main ()
-{
-#ifndef $as_decl_name
-#ifdef __cplusplus
- (void) $as_decl_use;
-#else
- (void) $as_decl_name;
-#endif
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- eval "$3=yes"
-else
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_decl
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
@@ -6401,16 +6357,65 @@ _ACEOF
fi
done
-ac_fn_c_check_decl "$LINENO" "qsort_r" "ac_cv_have_decl_qsort_r" "$ac_includes_default"
-if test "x$ac_cv_have_decl_qsort_r" = xyes; then :
- ac_have_decl=1
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for qsort_r with arg last" >&5
+$as_echo_n "checking for qsort_r with arg last... " >&6; }
+if ${ac_cv_libctf_qsort_r_arg_last+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_libctf_qsort_r_arg_last=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+ int do_not_call (const void *a, const void *b, void *arg)
+ {
+ return (a < b);
+ }
+ static int works = 0;
+ int conftest_compar (const void *a, const void *b, void *arg)
+ {
+ if (arg == do_not_call)
+ works = 1;
+ return (a < b);
+ }
+ int foo[2] = { 0, 1 };
+int
+main ()
+{
+qsort_r (foo, 2, sizeof (int), conftest_compar, do_not_call);
+ return (works == 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_libctf_qsort_r_arg_last=yes
else
- ac_have_decl=0
+ ac_cv_libctf_qsort_r_arg_last=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libctf_qsort_r_arg_last" >&5
+$as_echo "$ac_cv_libctf_qsort_r_arg_last" >&6; }
+
+if test $ac_cv_libctf_qsort_r_arg_last = yes; then
+
+$as_echo "#define HAVE_QSORT_R_ARG_LAST 1" >>confdefs.h
+
+fi
+ if test "${ac_cv_libctf_qsort_r_arg_last}" != yes; then
+ NEED_CTF_QSORT_R_TRUE=
+ NEED_CTF_QSORT_R_FALSE='#'
+else
+ NEED_CTF_QSORT_R_TRUE='#'
+ NEED_CTF_QSORT_R_FALSE=
fi
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_QSORT_R $ac_have_decl
-_ACEOF
case " $LIBOBJS " in
*" qsort_r.$ac_objext "* ) ;;
@@ -6561,6 +6566,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${NEED_CTF_QSORT_R_TRUE}" && test -z "${NEED_CTF_QSORT_R_FALSE}"; then
+ as_fn_error $? "conditional \"NEED_CTF_QSORT_R\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
diff --git a/libctf/configure.ac b/libctf/configure.ac
index 8fd5388d2a..185aa94378 100644
--- a/libctf/configure.ac
+++ b/libctf/configure.ac
@@ -90,7 +90,35 @@ fi
AC_C_BIGENDIAN
AC_CHECK_HEADERS(byteswap.h endian.h)
AC_CHECK_FUNCS(pread)
-AC_CHECK_DECLS([qsort_r])
+
+AC_CACHE_CHECK([for qsort_r with arg last], ac_cv_libctf_qsort_r_arg_last,
+[AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#include <stdlib.h>
+ int do_not_call (const void *a, const void *b, void *arg)
+ {
+ return (a < b);
+ }
+ static int works = 0;
+ int conftest_compar (const void *a, const void *b, void *arg)
+ {
+ if (arg == do_not_call)
+ works = 1;
+ return (a < b);
+ }
+ int foo[[2]] = { 0, 1 };],
+ [qsort_r (foo, 2, sizeof (int), conftest_compar, do_not_call);
+ return (works == 0);])],
+ [ac_cv_libctf_qsort_r_arg_last=yes],
+ [ac_cv_libctf_qsort_r_arg_last=no],
+ [ac_cv_libctf_qsort_r_arg_last=no])])
+
+if test $ac_cv_libctf_qsort_r_arg_last = yes; then
+ AC_DEFINE([HAVE_QSORT_R_ARG_LAST], 1,
+ [Whether a qsort_r exists with a void *arg as its last arg.])
+fi
+AM_CONDITIONAL(NEED_CTF_QSORT_R, test "${ac_cv_libctf_qsort_r_arg_last}" != yes)
+
AC_LIBOBJ([qsort_r])
AC_CONFIG_FILES(Makefile)
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index a238edb66b..90cd020b78 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -169,10 +169,11 @@ ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
modent++;
}
- qsort_r ((ctf_archive_modent_t *) ((char *) archdr
- + sizeof (struct ctf_archive)),
- le64toh (archdr->ctfa_nfiles),
- sizeof (struct ctf_archive_modent), sort_modent_by_name, nametbl);
+ ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
+ + sizeof (struct ctf_archive)),
+ le64toh (archdr->ctfa_nfiles),
+ sizeof (struct ctf_archive_modent), sort_modent_by_name,
+ nametbl);
/* Now the name table. */
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 227f62d8fd..3beed88712 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -344,7 +344,7 @@ ctf_update (ctf_file_t *fp)
}
assert (i == nvars);
- qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var, s0);
+ ctf_qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var, s0);
t += sizeof (ctf_varent_t) * nvars;
assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
diff --git a/libctf/ctf-decls.h b/libctf/ctf-decls.h
index 5e9ede4809..1f8aab11e4 100644
--- a/libctf/ctf-decls.h
+++ b/libctf/ctf-decls.h
@@ -22,12 +22,22 @@
#include "config.h"
-#if !HAVE_DECL_QSORT_R
#include <stddef.h>
-void qsort_r (void *base, size_t nmemb, size_t size,
+#if HAVE_QSORT_R_ARG_LAST
+#include <stdlib.h>
+
+inline void
+ctf_qsort_r (void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *, void *),
+ void *arg)
+{
+ qsort_r (base, nmemb, size, compar, arg);
+}
+#else
+void ctf_qsort_r (void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg);
-#endif /* !HAVE_DECL_QSORT_R */
+#endif /* !HAVE_QSORT_R_ARG_LAST */
#undef MAX
#undef MIN
diff --git a/libctf/qsort_r.c b/libctf/ctf-qsort_r.c
similarity index 99%
rename from libctf/qsort_r.c
rename to libctf/ctf-qsort_r.c
index 6c334fdaf3..6cb221d6f5 100644
--- a/libctf/qsort_r.c
+++ b/libctf/ctf-qsort_r.c
@@ -30,7 +30,7 @@
#include "ctf-decls.h"
#ifndef _LIBC
-# define _quicksort qsort_r
+# define _quicksort ctf_qsort_r
# define __compar_d_fn_t compar_d_fn_t
typedef int (*compar_d_fn_t) (const void *, const void *, void *);
#endif
--
2.21.0.237.gd0cfaa883d