QtBase  v6.3.1
qlibrary.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Copyright (C) 2021 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 #include "qlibrary.h"
41 #include "qlibrary_p.h"
42 
43 #include <q20algorithm.h>
44 #include <qbytearraymatcher.h>
45 #include <qdebug.h>
46 #include <qendian.h>
47 #include <qfile.h>
48 #include <qfileinfo.h>
49 #include <qjsondocument.h>
50 #include <qmap.h>
51 #include <qmutex.h>
53 #include <qstringlist.h>
54 
55 #ifdef Q_OS_MAC
56 # include <private/qcore_mac_p.h>
57 #endif
58 #include <private/qcoreapplication_p.h>
59 #include <private/qloggingregistry_p.h>
60 #include <private/qsystemerror_p.h>
61 
62 #include "qcoffpeparser_p.h"
63 #include "qelfparser_p.h"
64 #include "qfactoryloader_p.h"
65 #include "qmachparser_p.h"
66 
67 #include <qtcore_tracepoints_p.h>
68 
70 
71 // On Unix systema and on Windows with MinGW, we can mix and match debug and
72 // release plugins without problems. (unless compiled in debug-and-release mode
73 // - why?)
74 static constexpr bool PluginMustMatchQtDebug =
76 #if defined(Q_CC_MINGW)
77  && QT_CONFIG(debug_and_release)
78 #endif
79  ;
80 
81 #ifdef QT_NO_DEBUG
82 static constexpr bool QtBuildIsDebug = false;
83 #else
84 static constexpr bool QtBuildIsDebug = true;
85 #endif
86 
87 Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(qt_lcDebugPlugins, "QT_DEBUG_PLUGINS", "qt.core.plugin.loader")
88 static Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(lcDebugLibrary, "QT_DEBUG_PLUGINS", "qt.core.library")
89 
195 static QLibraryScanResult qt_find_pattern(const char *s, qsizetype s_len, QString *errMsg)
196 {
197  /*
198  We used to search from the end of the file so we'd skip the code and find
199  the read-only data that usually follows. Unfortunately, in debug builds,
200  the debug sections come after and are usually much bigger than everything
201  else, making this process slower than necessary with debug plugins.
202 
203  More importantly, the pattern string may exist in the debug information due
204  to it being used in the plugin in the first place.
205  */
206 #if defined(Q_OF_ELF)
207  return QElfParser::parse({s, s_len}, errMsg);
208 #elif defined(Q_OF_MACH_O)
209  return QMachOParser::parse(s, s_len, errMsg);
210 #elif defined(Q_OS_WIN)
211  return QCoffPeParser::parse({s, s_len}, errMsg);
212 #endif
213  static constexpr auto matcher = [] {
214  // QPluginMetaData::MagicString is not NUL-terminated, but
215  // qMakeStaticByteArrayMatcher requires its argument to be, so
216  // duplicate here, but statically check we didn't mess up:
217  constexpr auto &pattern = "QTMETADATA !";
218  constexpr auto magic = std::string_view(QPluginMetaData::MagicString,
220  static_assert(pattern == magic);
222  }();
223  qsizetype i = matcher.indexIn(s, s_len);
224  if (i < 0) {
225  *errMsg = QLibrary::tr("'%1' is not a Qt plugin").arg(*errMsg);
226  return QLibraryScanResult{};
227  }
228  i += sizeof(QPluginMetaData::MagicString);
229  return { i, s_len - i };
230 }
231 
232 /*
233  This opens the specified library, mmaps it into memory, and searches
234  for the QT_PLUGIN_VERIFICATION_DATA. The advantage of this approach is that
235  we can get the verification data without have to actually load the library.
236  This lets us detect mismatches more safely.
237 
238  Returns \c false if version information is not present, or if the
239  information could not be read.
240  Returns true if version information is present and successfully read.
241 */
242 static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib)
243 {
244  QFile file(library);
245  if (!file.open(QIODevice::ReadOnly)) {
246  if (lib)
247  lib->errorString = file.errorString();
248  qCWarning(qt_lcDebugPlugins, "%ls: cannot open: %ls", qUtf16Printable(library),
249  qUtf16Printable(file.errorString()));
250  return false;
251  }
252 
253  // Files can be bigger than the virtual memory size on 32-bit systems, so
254  // we limit to 512 MB there. For 64-bit, we allow up to 2^40 bytes.
255  constexpr qint64 MaxMemoryMapSize =
256  Q_INT64_C(1) << (sizeof(qsizetype) > 4 ? 40 : 29);
257 
258  qsizetype fdlen = qMin(file.size(), MaxMemoryMapSize);
259  const char *filedata = reinterpret_cast<char *>(file.map(0, fdlen));
260 
261 #ifdef Q_OS_UNIX
262  if (filedata == nullptr) {
263  // If we can't mmap(), then the dynamic loader won't be able to either.
264  // This can't be used as a plugin.
265  qCWarning(qt_lcDebugPlugins, "%ls: failed to map to memory: %ls",
266  qUtf16Printable(library), qUtf16Printable(file.errorString()));
267  return false;
268  }
269 #else
271  if (filedata == nullptr) {
272  // It's unknown at this point whether Windows supports LoadLibrary() on
273  // files that fail to CreateFileMapping / MapViewOfFile, so we err on
274  // the side of doing a regular read into memory (up to 64 MB).
275  data = file.read(64 * 1024 * 1024);
276  filedata = data.constData();
277  fdlen = data.size();
278  }
279 #endif
280 
282  QLibraryScanResult r = qt_find_pattern(filedata, fdlen, &errMsg);
283  if (r.length) {
284  if (!lib->metaData.parse(QByteArrayView(filedata + r.pos, r.length))) {
285  errMsg = lib->metaData.errorString();
286  qCWarning(qt_lcDebugPlugins, "Found invalid metadata in lib %ls: %ls",
287  qUtf16Printable(library), qUtf16Printable(errMsg));
288  } else {
289  qCDebug(qt_lcDebugPlugins, "Found metadata in lib %ls, metadata=\n%s\n",
290  qUtf16Printable(library),
292  return true;
293  }
294  } else {
295  qCDebug(qt_lcDebugPlugins, "Failed to find metadata in lib %ls: %ls",
296  qUtf16Printable(library), qUtf16Printable(errMsg));
297  }
298 
299  lib->errorString = QLibrary::tr("Failed to extract plugin meta data from '%1': %2")
300  .arg(library, errMsg);
301  return false;
302 }
303 
304 static void installCoverageTool(QLibraryPrivate *libPrivate)
305 {
306 #ifdef __COVERAGESCANNER__
307  /*
308  __COVERAGESCANNER__ is defined when Qt has been instrumented for code
309  coverage by TestCocoon. CoverageScanner is the name of the tool that
310  generates the code instrumentation.
311  This code is required here when code coverage analysis with TestCocoon
312  is enabled in order to allow the loading application to register the plugin
313  and then store its execution report. The execution report gathers information
314  about each part of the plugin's code that has been used when
315  the plugin was loaded by the launching application.
316  The execution report for the plugin will go to the same execution report
317  as the one defined for the application loading it.
318  */
319 
320  int ret = __coveragescanner_register_library(libPrivate->fileName.toLocal8Bit());
321 
322  if (ret >= 0) {
323  qDebug("coverage data for %ls registered",
324  qUtf16Printable(libPrivate->fileName));
325  } else {
326  qWarning("could not register %ls: error %d; coverage data may be incomplete",
327  qUtf16Printable(libPrivate->fileName),
328  ret);
329  }
330  }
331 #else
332  Q_UNUSED(libPrivate);
333 #endif
334 }
335 
337 {
338 public:
339  inline ~QLibraryStore();
340  static inline QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version, QLibrary::LoadHints loadHints);
341  static inline void releaseLibrary(QLibraryPrivate *lib);
342 
343  static inline void cleanup();
344 
345 private:
346  static inline QLibraryStore *instance();
347 
348  // all members and instance() are protected by qt_library_mutex
350  LibraryMap libraryMap;
351 };
352 
353 static QBasicMutex qt_library_mutex;
354 static QLibraryStore *qt_library_data = nullptr;
355 static bool qt_library_data_once;
356 
358 {
359  qt_library_data = nullptr;
360 }
361 
363 {
364  QLibraryStore *data = qt_library_data;
365  if (!data)
366  return;
367 
368  // find any libraries that are still loaded but have a no one attached to them
369  LibraryMap::Iterator it = data->libraryMap.begin();
370  for (; it != data->libraryMap.end(); ++it) {
371  QLibraryPrivate *lib = it.value();
372  if (lib->libraryRefCount.loadRelaxed() == 1) {
373  if (lib->libraryUnloadCount.loadRelaxed() > 0) {
374  Q_ASSERT(lib->pHnd.loadRelaxed());
375  lib->libraryUnloadCount.storeRelaxed(1);
376 #ifdef __GLIBC__
377  // glibc has a bug in unloading from global destructors
378  // see https://bugzilla.novell.com/show_bug.cgi?id=622977
379  // and http://sourceware.org/bugzilla/show_bug.cgi?id=11941
381 #elif defined(Q_OS_DARWIN)
382  // We cannot fully unload libraries, as we don't know if there are
383  // lingering references (in system threads e.g.) to Objective-C classes
384  // defined in the library.
386 #else
387  lib->unload();
388 #endif
389  }
390  delete lib;
391  it.value() = nullptr;
392  }
393  }
394 
395  // dump all objects that remain
396  if (lcDebugLibrary().isDebugEnabled()) {
397  for (QLibraryPrivate *lib : qAsConst(data->libraryMap)) {
398  if (lib)
399  qDebug(lcDebugLibrary)
400  << "On QtCore unload," << lib->fileName << "was leaked, with"
401  << lib->libraryRefCount.loadRelaxed() << "users";
402  }
403  }
404 
405  delete data;
406 }
407 
408 static void qlibraryCleanup()
409 {
411 }
412 Q_DESTRUCTOR_FUNCTION(qlibraryCleanup)
413 
414 // must be called with a locked mutex
415 QLibraryStore *QLibraryStore::instance()
416 {
417  if (Q_UNLIKELY(!qt_library_data_once && !qt_library_data)) {
418  // only create once per process lifetime
419  qt_library_data = new QLibraryStore;
420  qt_library_data_once = true;
421  }
422  return qt_library_data;
423 }
424 
426  QLibrary::LoadHints loadHints)
427 {
428  QMutexLocker locker(&qt_library_mutex);
429  QLibraryStore *data = instance();
430 
431  // check if this library is already loaded
432  QLibraryPrivate *lib = nullptr;
433  if (Q_LIKELY(data)) {
434  lib = data->libraryMap.value(fileName);
435  if (lib)
436  lib->mergeLoadHints(loadHints);
437  }
438  if (!lib)
439  lib = new QLibraryPrivate(fileName, version, loadHints);
440 
441  // track this library
442  if (Q_LIKELY(data) && !fileName.isEmpty())
443  data->libraryMap.insert(fileName, lib);
444 
445  lib->libraryRefCount.ref();
446  return lib;
447 }
448 
450 {
451  QMutexLocker locker(&qt_library_mutex);
452  QLibraryStore *data = instance();
453 
454  if (lib->libraryRefCount.deref()) {
455  // still in use
456  return;
457  }
458 
459  // no one else is using
460  Q_ASSERT(lib->libraryUnloadCount.loadRelaxed() == 0);
461 
462  if (Q_LIKELY(data) && !lib->fileName.isEmpty()) {
463  QLibraryPrivate *that = data->libraryMap.take(lib->fileName);
464  Q_ASSERT(lib == that);
465  Q_UNUSED(that);
466  }
467  delete lib;
468 }
469 
470 QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints)
471  : fileName(canonicalFileName), fullVersion(version), pluginState(MightBeAPlugin)
472 {
473  loadHintsInt.storeRelaxed(loadHints.toInt());
474  if (canonicalFileName.isEmpty())
475  errorString = QLibrary::tr("The shared library was not found.");
476 }
477 
479  QLibrary::LoadHints loadHints)
480 {
482 }
483 
484 QLibraryPrivate::~QLibraryPrivate()
485 {
486 }
487 
488 void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
489 {
490  // if the library is already loaded, we can't change the load hints
491  if (pHnd.loadRelaxed())
492  return;
493 
494  loadHintsInt.storeRelaxed(lh.toInt());
495 }
496 
497 QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
498 {
499  if (!pHnd.loadRelaxed())
500  return nullptr;
501  return resolve_sys(symbol);
502 }
503 
504 void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh)
505 {
506  // this locks a global mutex
507  QMutexLocker lock(&qt_library_mutex);
508  mergeLoadHints(lh);
509 }
510 
512 {
513  // first, check if the instance is cached and hasn't been deleted
514  QObject *obj = [&](){ QMutexLocker locker(&mutex); return inst.data(); }();
515  if (obj)
516  return obj;
517 
518  // We need to call the plugin's factory function. Is that cached?
519  // skip increasing the reference count (why? -Thiago)
521  if (!factory)
522  factory = loadPlugin();
523 
524  if (!factory)
525  return nullptr;
526 
527  obj = factory();
528 
529  // cache again
530  QMutexLocker locker(&mutex);
531  if (inst)
532  obj = inst;
533  else
534  inst = obj;
535  return obj;
536 }
537 
539 {
540  if (pHnd.loadRelaxed()) {
541  libraryUnloadCount.ref();
542  return true;
543  }
544  if (fileName.isEmpty())
545  return false;
546 
547  Q_TRACE(QLibraryPrivate_load_entry, fileName);
548 
549  bool ret = load_sys();
550  qCDebug(lcDebugLibrary)
551  << fileName
552  << (ret ? "loaded library" : qUtf8Printable(u"cannot load: " + errorString));
553  if (ret) {
554  //when loading a library we add a reference to it so that the QLibraryPrivate won't get deleted
555  //this allows to unload the library at a later time
556  libraryUnloadCount.ref();
557  libraryRefCount.ref();
558  installCoverageTool(this);
559  }
560 
561  Q_TRACE(QLibraryPrivate_load_exit, ret);
562 
563  return ret;
564 }
565 
567 {
568  if (!pHnd.loadRelaxed())
569  return false;
570  if (libraryUnloadCount.loadRelaxed() > 0 && !libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
571  QMutexLocker locker(&mutex);
572  delete inst.data();
573  if (flag == NoUnloadSys || unload_sys()) {
574  qCDebug(lcDebugLibrary) << fileName << "unloaded library"
575  << (flag == NoUnloadSys ? "(faked)" : "");
576  // when the library is unloaded, we release the reference on it so that 'this'
577  // can get deleted
578  libraryRefCount.deref();
579  pHnd.storeRelaxed(nullptr);
580  instanceFactory.storeRelaxed(nullptr);
581  return true;
582  }
583  }
584 
585  return false;
586 }
587 
589 {
591 }
592 
594 {
595  if (auto ptr = instanceFactory.loadAcquire()) {
596  libraryUnloadCount.ref();
597  return ptr;
598  }
599  if (pluginState == IsNotAPlugin)
600  return nullptr;
601  if (load()) {
602  auto ptr = reinterpret_cast<QtPluginInstanceFunction>(resolve("qt_plugin_instance"));
603  instanceFactory.storeRelease(ptr); // two threads may store the same value
604  return ptr;
605  }
606  qCDebug(qt_lcDebugPlugins) << "QLibraryPrivate::loadPlugin failed on" << fileName << ":" << errorString;
607  pluginState = IsNotAPlugin;
608  return nullptr;
609 }
610 
627 {
628 #if defined(Q_OS_WIN)
630 #else // Generic Unix
631 # if defined(Q_OS_DARWIN)
632  // On Apple platforms, dylib look like libmylib.1.0.0.dylib
633  if (fileName.endsWith(QLatin1String(".dylib")))
634  return true;
635 # endif
636  QString completeSuffix = QFileInfo(fileName).completeSuffix();
637  if (completeSuffix.isEmpty())
638  return false;
639 
640  // if this throws an empty-array error, you need to fix the #ifdef's:
641  const QLatin1String candidates[] = {
642 # if defined(Q_OS_HPUX)
643 /*
644  See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF":
645  "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit),
646  the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix."
647 */
648  QLatin1String("sl"),
649 # if defined __ia64
650  QLatin1String("so"),
651 # endif
652 # elif defined(Q_OS_AIX)
653  QLatin1String("a"),
654  QLatin1String("so"),
655 # elif defined(Q_OS_DARWIN)
656  QLatin1String("so"),
657  QLatin1String("bundle"),
658 # elif defined(Q_OS_UNIX)
659  QLatin1String("so"),
660 # endif
661  }; // candidates
662 
663  auto isValidSuffix = [&candidates](QStringView s) {
664  return std::find(std::begin(candidates), std::end(candidates), s) != std::end(candidates);
665  };
666 
667  // Examples of valid library names:
668  // libfoo.so
669  // libfoo.so.0
670  // libfoo.so.0.3
671  // libfoo-0.3.so
672  // libfoo-0.3.so.0.3.0
673 
674  auto suffixes = qTokenize(completeSuffix, u'.');
675  auto it = suffixes.begin();
676  const auto end = suffixes.end();
677 
678  auto isNumeric = [](QStringView s) { bool ok; (void)s.toInt(&ok); return ok; };
679 
680  while (it != end) {
681  if (isValidSuffix(*it++))
682  return q20::ranges::all_of(it, end, isNumeric);
683  }
684  return false; // no valid suffix found
685 #endif
686 }
687 
688 static bool qt_get_metadata(QLibraryPrivate *priv, QString *errMsg)
689 {
690  auto error = [=](QString &&explanation) {
691  *errMsg = QLibrary::tr("'%1' is not a Qt plugin (%2)").arg(priv->fileName, std::move(explanation));
692  return false;
693  };
694 
695  QPluginMetaData metaData;
696  QFunctionPointer pfn = priv->resolve("qt_plugin_query_metadata_v2");
697  if (pfn) {
698  metaData = reinterpret_cast<QPluginMetaData (*)()>(pfn)();
699 #if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
700  } else if ((pfn = priv->resolve("qt_plugin_query_metadata"))) {
701  metaData = reinterpret_cast<QPluginMetaData (*)()>(pfn)();
702  if (metaData.size < sizeof(QPluginMetaData::MagicHeader))
703  return error(QLibrary::tr("metadata too small"));
704 
705  // adjust the meta data to point to the header
706  auto data = reinterpret_cast<const char *>(metaData.data);
708  metaData.data = data;
709  metaData.size -= sizeof(QPluginMetaData::MagicString);
710 #endif
711  } else {
712  return error(QLibrary::tr("entrypoint to query the plugin meta data not found"));
713  }
714 
715  if (metaData.size < sizeof(QPluginMetaData::Header))
716  return error(QLibrary::tr("metadata too small"));
717 
718  if (priv->metaData.parse(metaData))
719  return true;
720  *errMsg = priv->metaData.errorString();
721  return false;
722 }
723 
725 {
726  if (pluginState == MightBeAPlugin)
728 
729  return pluginState == IsAPlugin;
730 }
731 
733 {
734  QMutexLocker locker(&mutex);
735  errorString.clear();
736  if (pluginState != MightBeAPlugin)
737  return;
738 
739  bool success = false;
740 
741 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
742  if (fileName.endsWith(QLatin1String(".debug"))) {
743  // refuse to load a file that ends in .debug
744  // these are the debug symbols from the libraries
745  // the problem is that they are valid shared library files
746  // and dlopen is known to crash while opening them
747 
748  // pretend we didn't see the file
749  errorString = QLibrary::tr("The shared library was not found.");
750  pluginState = IsNotAPlugin;
751  return;
752  }
753 #endif
754 
755  if (!pHnd.loadRelaxed()) {
756  // scan for the plugin metadata without loading
757  success = findPatternUnloaded(fileName, this);
758  } else {
759  // library is already loaded (probably via QLibrary)
760  // simply get the target function and call it.
761  success = qt_get_metadata(this, &errorString);
762  }
763 
764  if (!success) {
765  if (errorString.isEmpty()) {
766  if (fileName.isEmpty())
767  errorString = QLibrary::tr("The shared library was not found.");
768  else
769  errorString = QLibrary::tr("The file '%1' is not a valid Qt plugin.").arg(fileName);
770  }
771  pluginState = IsNotAPlugin;
772  return;
773  }
774 
775  pluginState = IsNotAPlugin; // be pessimistic
776 
779  if ((qt_version & 0x00ff00) > (QT_VERSION & 0x00ff00) || (qt_version & 0xff0000) != (QT_VERSION & 0xff0000)) {
780  qCWarning(qt_lcDebugPlugins, "In %s:\n"
781  " Plugin uses incompatible Qt library (%d.%d.%d) [%s]",
782  QFile::encodeName(fileName).constData(),
783  (qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff,
784  debug ? "debug" : "release");
785  errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]")
786  .arg(fileName,
787  QString::number((qt_version & 0xff0000) >> 16),
788  QString::number((qt_version & 0xff00) >> 8),
789  QString::number(qt_version & 0xff),
790  debug ? QLatin1String("debug") : QLatin1String("release"));
791  } else if (PluginMustMatchQtDebug && debug != QtBuildIsDebug) {
792  //don't issue a qWarning since we will hopefully find a non-debug? --Sam
793  errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library."
794  " (Cannot mix debug and release libraries.)").arg(fileName);
795  } else {
796  pluginState = IsAPlugin;
797  }
798 }
799 
811 {
812  if (!d)
813  return false;
814  if (d.tag() == Loaded)
815  return d->pHnd.loadRelaxed();
816  else
817  d.setTag(Loaded);
818  return d->load();
819 }
820 
837 {
838  if (d.tag() == Loaded) {
839  d.setTag(NotLoaded);
840  return d->unload();
841  }
842  return false;
843 }
844 
850 bool QLibrary::isLoaded() const
851 {
852  return d && d->pHnd.loadRelaxed();
853 }
854 
855 
860 {
861 }
862 
863 
874 {
876 }
877 
889 {
891 }
892 
904  : QObject(parent)
905 {
907 }
908 
918 {
919  if (d)
920  d->release();
921 }
922 
945 {
946  QLibrary::LoadHints lh;
947  if (d) {
948  lh = d->loadHints();
949  d->release();
950  d = {};
951  }
953 }
954 
956 {
957  if (d) {
958  QMutexLocker locker(&d->mutex);
959  return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
960  }
961  return QString();
962 }
963 
974 {
975  QLibrary::LoadHints lh;
976  if (d) {
977  lh = d->loadHints();
978  d->release();
979  d = {};
980  }
981  d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString(), lh);
982 }
983 
994 {
995  QLibrary::LoadHints lh;
996  if (d) {
997  lh = d->loadHints();
998  d->release();
999  d = {};
1000  }
1002 }
1003 
1024 QFunctionPointer QLibrary::resolve(const char *symbol)
1025 {
1026  if (!isLoaded() && !load())
1027  return nullptr;
1028  return d->resolve(symbol);
1029 }
1030 
1044 QFunctionPointer QLibrary::resolve(const QString &fileName, const char *symbol)
1045 {
1047  return library.resolve(symbol);
1048 }
1049 
1064 QFunctionPointer QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
1065 {
1066  QLibrary library(fileName, verNum);
1067  return library.resolve(symbol);
1068 }
1069 
1085 QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol)
1086 {
1088  return library.resolve(symbol);
1089 }
1090 
1098 {
1099  QString str;
1100  if (d) {
1101  QMutexLocker locker(&d->mutex);
1102  str = d->errorString;
1103  }
1104  return str.isEmpty() ? tr("Unknown error") : str;
1105 }
1106 
1142 void QLibrary::setLoadHints(LoadHints hints)
1143 {
1144  if (!d) {
1145  d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
1146  d->errorString.clear();
1147  }
1148  d->setLoadHints(hints);
1149 }
1150 
1151 QLibrary::LoadHints QLibrary::loadHints() const
1152 {
1153  return d ? d->loadHints() : QLibrary::LoadHints();
1154 }
1155 
1156 /* Internal, for debugging */
1158 {
1159  static int debug_env = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)("QT_DEBUG_PLUGINS");
1160  return debug_env != 0;
1161 }
1162 
1164 
1165 #include "moc_qlibrary.cpp"
small capitals from c petite p scientific f u
Definition: afcover.h:88
FT_Error error
Definition: cffdrivr.c:657
FT_Library library
Definition: cffdrivr.c:660
bool ref() noexcept
Definition: qbasicatomic.h:101
bool deref() noexcept
Definition: qbasicatomic.h:102
void storeRelaxed(T newValue) noexcept
Definition: qbasicatomic.h:91
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
Type loadAcquire() const noexcept
Definition: qbasicatomic.h:233
Type loadRelaxed() const noexcept
Definition: qbasicatomic.h:226
void storeRelaxed(Type newValue) noexcept
Definition: qbasicatomic.h:227
void storeRelease(Type newValue) noexcept
Definition: qbasicatomic.h:234
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
char * data()
const char * constData() const noexcept
Definition: qbytearray.h:144
qint64 toInteger(qint64 defaultValue=0) const
Definition: qcborvalue.h:228
bool toBool(bool defaultValue=false) const
Definition: qcborvalue.h:230
uchar * map(qint64 offset, qint64 size, MemoryMapFlags flags=NoOptions)
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
bool open(OpenMode flags) override
Definition: qfile.cpp:897
static QByteArray encodeName(const QString &fileName)
Definition: qfile.h:159
qint64 size() const override
Definition: qfile.cpp:1172
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:57
QString completeSuffix() const
Definition: qfileinfo.cpp:854
QString errorString() const
Definition: qiodevice.cpp:2169
qint64 read(char *data, qint64 maxlen)
Definition: qiodevice.cpp:1030
The QJsonDocument class provides a way to read and write JSON documents.
Definition: qjsondocument.h:83
QByteArray toJson(JsonFormat format=Indented) const
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
The QLibrary class loads shared libraries at runtime.
Definition: qlibrary.h:53
bool load()
Definition: qlibrary.cpp:810
LoadHints loadHints
Give the load() function some hints on how it should behave.
Definition: qlibrary.h:56
QString fileName
the file name of the library
Definition: qlibrary.h:55
static bool isLibrary(const QString &fileName)
Definition: qlibrary.cpp:626
void setFileNameAndVersion(const QString &fileName, int verNum)
Definition: qlibrary.cpp:973
void setFileName(const QString &fileName)
Definition: qlibrary.cpp:944
bool isLoaded() const
Definition: qlibrary.cpp:850
bool unload()
Definition: qlibrary.cpp:836
void setLoadHints(LoadHints hints)
Definition: qlibrary.cpp:1142
QLibrary(QObject *parent=nullptr)
Definition: qlibrary.cpp:859
QFunctionPointer resolve(const char *symbol)
Definition: qlibrary.cpp:1024
QString errorString() const
Definition: qlibrary.cpp:1097
QString errorString
Definition: qlibrary_p.h:116
bool unload(UnloadFlag flag=UnloadSys)
Definition: qlibrary.cpp:566
QString qualifiedFileName
Definition: qlibrary_p.h:117
QtPluginInstanceFunction loadPlugin()
Definition: qlibrary.cpp:593
QAtomicPointer< std::remove_pointer< Handle >::type > pHnd
Definition: qlibrary_p.h:110
void setLoadHints(QLibrary::LoadHints lh)
Definition: qlibrary.cpp:504
const QString fileName
Definition: qlibrary_p.h:90
void updatePluginState()
Definition: qlibrary.cpp:732
QAtomicPointer< std::remove_pointer< QtPluginInstanceFunction >::type > instanceFactory
Definition: qlibrary_p.h:109
QPluginParsedMetaData metaData
Definition: qlibrary_p.h:115
QFunctionPointer resolve(const char *)
Definition: qlibrary.cpp:497
QPointer< QObject > inst
Definition: qlibrary_p.h:114
QObject * pluginInstance()
Definition: qlibrary.cpp:511
static QLibraryPrivate * findOrCreate(const QString &fileName, const QString &version=QString(), QLibrary::LoadHints loadHints={ })
Definition: qlibrary.cpp:478
QLibrary::LoadHints loadHints() const
Definition: qlibrary_p.h:99
static void cleanup()
Definition: qlibrary.cpp:362
static void releaseLibrary(QLibraryPrivate *lib)
Definition: qlibrary.cpp:449
static QLibraryPrivate * findOrCreate(const QString &fileName, const QString &version, QLibrary::LoadHints loadHints)
Definition: qlibrary.cpp:425
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
static constexpr OSType currentType()
QCborValue value(QtPluginMetaDataKeys k) const
bool parse(QByteArrayView input)
QJsonObject toJson() const
QString errorString() const
T * data() const
Definition: qpointer.h:76
template< size_t N > QStaticByteArrayMatcher qMakeStaticByteArrayMatcher(const char(&pattern)[N])
The QString class provides a Unicode character string.
Definition: qstring.h:388
void clear()
Definition: qstring.h:1240
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5143
bool isEmpty() const
Definition: qstring.h:1216
QByteArray toLocal8Bit() const &
Definition: qstring.h:753
static QString number(int, int base=10)
Definition: qstring.cpp:7538
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
void setTag(Tag tag)
Tag tag() const noexcept
QString str
[2]
bool parse()
int const char * version
Definition: zlib.h:814
auto it unsigned count const
Definition: hb-iter.hh:848
@ CaseInsensitive
Definition: qnamespace.h:1283
constexpr struct q20::ranges::@310 all_of
#define QString()
Definition: parse-defines.h:51
void
Definition: png.h:1080
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
#define QT_VERSION
Definition: qglobal.h:58
ptrdiff_t qsizetype
Definition: qglobal.h:308
unsigned int uint
Definition: qglobal.h:334
long long qint64
Definition: qglobal.h:298
#define QT_CONFIG(feature)
Definition: qglobal.h:107
#define Q_INT64_C(c)
Definition: qglobal.h:295
bool qt_debug_component()
Definition: qlibrary.cpp:1157
qsizetype QString * errMsg
Definition: qlibrary.cpp:196
qsizetype i
Definition: qlibrary.cpp:223
qsizetype s_len
Definition: qlibrary.cpp:195
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(name, env, categoryName)
GLboolean r
[2]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
GLdouble s
[6]
Definition: qopenglext.h:235
GLubyte * pattern
Definition: qopenglext.h:2744
QObject *(* QtPluginInstanceFunction)()
Definition: qplugin.h:66
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
int QT_PREPEND_NAMESPACE(QSharedMemoryPrivate)
constexpr auto qTokenize(Haystack &&h, Needle &&n, Flags...flags) noexcept(QtPrivate::Tok::is_nothrow_constructible_from< Haystack, Needle >::value) -> decltype(QtPrivate::Tok::TokenizerResult< Haystack, Needle >{std::forward< Haystack >(h), std::forward< Needle >(n), flags...})
#define tr(X)
#define Q_TRACE(x,...)
Definition: qtrace_p.h:136
Q_UNUSED(salary)
[21]
QFile file
[0]
QReadWriteLock lock
[0]
QItemEditorFactory * factory
QStringList::Iterator it
const void * data
Definition: qplugin.h:132
size_t size
Definition: qplugin.h:136
static constexpr char MagicString[]
Definition: qplugin.h:70
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
QDomElement find(const QString &tagName, const QDomElement &e)
Definition: main.cpp:39