From 864a546af6e1c17e0de2dc2be6da105f454b6e54 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Fri, 21 Jun 2019 20:27:31 -0400 Subject: [PATCH] Build with -fvisibility=hidden when supported --- ChangeLog | 10 ++++++ README-maintainer | 6 ++++ TODO | 3 -- autofiles.sums | 2 +- configure | 55 ++++++++++++++++++++++++++++++ configure.ac | 27 +++++++++++++++ include/qpdf/DLL.h | 8 ++--- include/qpdf/InputSource.hh | 4 +-- include/qpdf/Pipeline.hh | 2 +- include/qpdf/Pl_DCT.hh | 2 +- include/qpdf/QPDFExc.hh | 2 +- include/qpdf/QPDFObjectHandle.hh | 4 +-- include/qpdf/QPDFSystemError.hh | 2 +- include/qpdf/QPDFWriter.hh | 2 +- include/qpdf/RandomDataProvider.hh | 3 +- 15 files changed, 114 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index e555a10a..b6d98291 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2019-06-21 Jay Berkenbilt + * When supported, qpdf builds with -fvisibility=hidden, which + removes non-exported symbols from the shared library in a manner + similar to how Windows DLLs work. This is better for performance + and also better for safety and protection of private interfaces. + See https://gcc.gnu.org/wiki/Visibility. *NOTE*: If you are + getting linker errors trying to catch exceptions or derive things + from a base class in the qpdf library, it's possible that a + QPDF_DLL_CLASS declaration is missing somewhere. Please report + this as a bug at https://github.com/qpdf/qpdf/issues. + * Source-level incompatibility: remove the version QPDF::copyForeignObject with an unused boolean parameter. If you were, for some reason, calling this, just take the parameter away. diff --git a/README-maintainer b/README-maintainer index 58ffbf80..3bb2b659 100644 --- a/README-maintainer +++ b/README-maintainer @@ -64,6 +64,12 @@ CODING RULES * Use QIntC for type conversions -- see casting policy in docs. +* Use QPDF_DLL on all methods that are to be exported in the shared + library/DLL. Use QPDF_DLL_CLASS for all classes whose type + information is needed. This is important for exception classes and + it seems also for classes that are intended to be subclassed across + the shared library boundary. + RELEASE PREPARATION * Each year, update copyright notices. Just do a case-insensitive diff --git a/TODO b/TODO index 6fc5c1ac..d32d21d7 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,6 @@ Next ABI ======== - * Build with -fvisibility=hidden by default. Fix QPDF_DLL. See #302 - for discussion. See also https://gcc.gnu.org/wiki/Visibility - * Check all classes that don't use the Members pattern and see if they should be converted. Most of the pipeline classes should be converted. diff --git a/autofiles.sums b/autofiles.sums index 32e16a13..dead1791 100644 --- a/autofiles.sums +++ b/autofiles.sums @@ -1,4 +1,4 @@ -3bb3daeee89ecd7770434a3357d2f4bd6ad415de8cdacc90d5e1fce39e1b3a91 configure.ac +5b50c329677bcc8c1d5a8b3654b79ccca8bbe80a452cc4bb14938370f316327a configure.ac 35bc5c645dc42d47f2daeea06f8f3e767c8a1aee6a35eb2b4854fd2ce66c3413 m4/ax_random_device.m4 37f8897d5f68d7d484e5457832a8f190ddb7507fa2a467cb7ee2be40a4364643 m4/libtool.m4 e77ebba8361b36f14b4d0927173a034b98c5d05049697a9ded84d85eb99a7990 m4/ltoptions.m4 diff --git a/configure b/configure index edb46e9a..0cd1b0be 100755 --- a/configure +++ b/configure @@ -15840,6 +15840,61 @@ LT_REVISION=2 LT_SONAME=$(expr $LT_CURRENT - $LT_AGE) +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fvisibility=hidden" >&5 +$as_echo_n "checking for -fvisibility=hidden... " >&6; } +try_flags=-fvisibility=hidden +oCXXFLAGS=$CXXFLAGS +CXXFLAGS="$CXXFLAGS $try_flags" +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +class X +{ + public: + __attribute__ ((visibility ("default"))) + X() {} + __attribute__ ((visibility ("default"))) + void f() {} +}; + +int +main () +{ +X x; x.f(); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + qpdf_VISIBILITY_HIDDEN=1 +else + qpdf_VISIBILITY_HIDDEN=0 +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test "$qpdf_VISIBILITY_HIDDEN" = "0"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS=$oCXXFLAGS +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + CFLAGS="$CFLAGS $try_flags" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use insecure random numbers" >&5 +$as_echo_n "checking whether to use insecure random numbers... " >&6; } # Check whether --enable-insecure-random was given. if test "${enable_insecure_random+set}" = set; then : enableval=$enable_insecure_random; if test "$enableval" = "yes"; then diff --git a/configure.ac b/configure.ac index 541b8c52..9cb99184 100644 --- a/configure.ac +++ b/configure.ac @@ -60,6 +60,33 @@ AC_SUBST(LT_AGE) LT_SONAME=$(expr $LT_CURRENT - $LT_AGE) AC_SUBST(LT_SONAME) +AC_MSG_CHECKING(for -fvisibility=hidden) +try_flags=-fvisibility=hidden +oCXXFLAGS=$CXXFLAGS +CXXFLAGS="$CXXFLAGS $try_flags" +AC_LANG_PUSH([C++]) +AC_LINK_IFELSE([AC_LANG_PROGRAM( + [[class X +{ + public: + __attribute__ ((visibility ("default"))) + X() {} + __attribute__ ((visibility ("default"))) + void f() {} +}; + ]],[[X x; x.f();]])], + [qpdf_VISIBILITY_HIDDEN=1], + [qpdf_VISIBILITY_HIDDEN=0]) +AC_LANG_POP +if test "$qpdf_VISIBILITY_HIDDEN" = "0"; then + AC_MSG_RESULT(no) + CXXFLAGS=$oCXXFLAGS +else + AC_MSG_RESULT(yes) + CFLAGS="$CFLAGS $try_flags" +fi + +AC_MSG_CHECKING(whether to use insecure random numbers) AC_ARG_ENABLE(insecure-random, AS_HELP_STRING([--enable-insecure-random], [whether to use stdlib's random number generator (default is no)]), diff --git a/include/qpdf/DLL.h b/include/qpdf/DLL.h index 1e5d8a1a..7b9b00a8 100644 --- a/include/qpdf/DLL.h +++ b/include/qpdf/DLL.h @@ -23,15 +23,15 @@ #ifndef QPDF_DLL_HH #define QPDF_DLL_HH -#if defined(_WIN32) && defined(DLL_EXPORT) +#if (defined _WIN32 || defined __CYGWIN__) && defined(DLL_EXPORT) # define QPDF_DLL __declspec(dllexport) -# define QPDF_DLL_EXCEPTION +# define QPDF_DLL_CLASS #elif __GNUC__ >= 4 # define QPDF_DLL __attribute__ ((visibility ("default"))) -# define QPDF_DLL_EXCEPTION __attribute__ ((visibility ("default"))) +# define QPDF_DLL_CLASS __attribute__ ((visibility ("default"))) #else # define QPDF_DLL -# define QPDF_DLL_EXCEPTION +# define QPDF_DLL_CLASS #endif #endif /* QPDF_DLL_HH */ diff --git a/include/qpdf/InputSource.hh b/include/qpdf/InputSource.hh index 8465ad55..3d0d9aaf 100644 --- a/include/qpdf/InputSource.hh +++ b/include/qpdf/InputSource.hh @@ -27,7 +27,7 @@ #include #include -class InputSource +class QPDF_DLL_CLASS InputSource { public: QPDF_DLL @@ -40,7 +40,7 @@ class InputSource { } - class Finder + class QPDF_DLL_CLASS Finder { public: Finder() diff --git a/include/qpdf/Pipeline.hh b/include/qpdf/Pipeline.hh index b7bc5a7e..a5440a27 100644 --- a/include/qpdf/Pipeline.hh +++ b/include/qpdf/Pipeline.hh @@ -47,7 +47,7 @@ #include #include -class Pipeline +class QPDF_DLL_CLASS Pipeline { public: QPDF_DLL diff --git a/include/qpdf/Pl_DCT.hh b/include/qpdf/Pl_DCT.hh index 665a2b01..1827fa80 100644 --- a/include/qpdf/Pl_DCT.hh +++ b/include/qpdf/Pl_DCT.hh @@ -33,7 +33,7 @@ class Pl_DCT: public Pipeline QPDF_DLL Pl_DCT(char const* identifier, Pipeline* next); - class CompressConfig + class QPDF_DLL_CLASS CompressConfig { public: CompressConfig() diff --git a/include/qpdf/QPDFExc.hh b/include/qpdf/QPDFExc.hh index c538eb4d..188ede29 100644 --- a/include/qpdf/QPDFExc.hh +++ b/include/qpdf/QPDFExc.hh @@ -29,7 +29,7 @@ #include #include -class QPDF_DLL_EXCEPTION QPDFExc: public std::runtime_error +class QPDF_DLL_CLASS QPDFExc: public std::runtime_error { public: QPDF_DLL diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 4ee0b5a0..28f6f491 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -54,7 +54,7 @@ class QPDFObjectHandle // alternative way of associating stream data with a stream. See // comments on replaceStreamData and newStream for additional // details. - class StreamDataProvider + class QPDF_DLL_CLASS StreamDataProvider { public: QPDF_DLL @@ -99,7 +99,7 @@ class QPDFObjectHandle // string token will also work. The correct way to construct a // string token that would write the literal value (str) is // QPDFTokenizer::Token(QPDFTokenizer::tt_string, "str"). - class TokenFilter + class QPDF_DLL_CLASS TokenFilter { public: QPDF_DLL diff --git a/include/qpdf/QPDFSystemError.hh b/include/qpdf/QPDFSystemError.hh index cef8ea08..e8ea09eb 100644 --- a/include/qpdf/QPDFSystemError.hh +++ b/include/qpdf/QPDFSystemError.hh @@ -29,7 +29,7 @@ #include #include -class QPDF_DLL_EXCEPTION QPDFSystemError: public std::runtime_error +class QPDF_DLL_CLASS QPDFSystemError: public std::runtime_error { public: QPDF_DLL diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 2ac00582..703d752f 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -76,7 +76,7 @@ class QPDFWriter QPDF_DLL ~QPDFWriter(); - class ProgressReporter + class QPDF_DLL_CLASS ProgressReporter { public: virtual ~ProgressReporter() diff --git a/include/qpdf/RandomDataProvider.hh b/include/qpdf/RandomDataProvider.hh index c3a519aa..2213b7c4 100644 --- a/include/qpdf/RandomDataProvider.hh +++ b/include/qpdf/RandomDataProvider.hh @@ -22,9 +22,10 @@ #ifndef RANDOMDATAPROVIDER_HH #define RANDOMDATAPROVIDER_HH +#include #include // for size_t -class RandomDataProvider +class QPDF_DLL_CLASS RandomDataProvider { public: virtual ~RandomDataProvider()