1
2 /****************************************************************************
3 **
4 ** Copyright (C) 2015 The Qt Company Ltd.
5 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
16 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
21 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
22 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
23 ** following information to ensure the GNU Lesser General Public License
24 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
25 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26 **
27 ** As a special exception, The Qt Company gives you certain additional
28 ** rights. These rights are described in The Qt Company LGPL Exception
29 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
30 **
31 ** GNU General Public License Usage
32 ** Alternatively, this file may be used under the terms of the GNU
33 ** General Public License version 3.0 as published by the Free Software
34 ** Foundation and appearing in the file LICENSE.GPL included in the
35 ** packaging of this file. Please review the following information to
36 ** ensure the GNU General Public License version 3.0 requirements will be
37 ** met: http://www.gnu.org/copyleft/gpl.html.
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42 #include "qplatformdefs.h"
43 #include "qlibrary.h"
44
45 #ifndef QT_NO_LIBRARY
46
47 #include "qlibrary_p.h"
48 #include <qstringlist.h>
49 #include <qfile.h>
50 #include <qfileinfo.h>
51 #include <qmutex.h>
52 #include <qmap.h>
53 #include <qsettings.h>
54 #include <qdatetime.h>
55 #include <private/qcoreapplication_p.h>
56 #ifdef Q_OS_MAC
57 # include <private/qcore_mac_p.h>
58 #endif
59 #ifndef NO_ERRNO_H
60 #include <errno.h>
61 #endif // NO_ERROR_H
62 #include <qdebug.h>
63 #include <qvector.h>
64 #include <qdir.h>
65 #include "qelfparser_p.h"
66
67 QT_BEGIN_NAMESPACE
68
69 #ifdef QT_NO_DEBUG
70 # define QLIBRARY_AS_DEBUG false
71 #else
72 # define QLIBRARY_AS_DEBUG true
73 #endif
74
75 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
76 // We don't use separate debug and release libs on UNIX, so we want
77 // to allow loading plugins, regardless of how they were built.
78 # define QT_NO_DEBUG_PLUGIN_CHECK
79 #endif
80
81 Q_GLOBAL_STATIC(QMutex, qt_library_mutex)
82
83 /*!
84 \class QLibrary
85 \reentrant
86 \brief The QLibrary class loads shared libraries at runtime.
87
88
89 \ingroup plugins
90
91 An instance of a QLibrary object operates on a single shared
92 object file (which we call a "library", but is also known as a
93 "DLL"). A QLibrary provides access to the functionality in the
94 library in a platform independent way. You can either pass a file
95 name in the constructor, or set it explicitly with setFileName().
96 When loading the library, QLibrary searches in all the
97 system-specific library locations (e.g. \c LD_LIBRARY_PATH on
98 Unix), unless the file name has an absolute path. If the file
99 cannot be found, QLibrary tries the name with different
100 platform-specific file suffixes, like ".so" on Unix, ".dylib" on
101 the Mac, or ".dll" on Windows and Symbian. This makes it possible
102 to specify shared libraries that are only identified by their
103 basename (i.e. without their suffix), so the same code will work
104 on different operating systems.
105
106 The most important functions are load() to dynamically load the
107 library file, isLoaded() to check whether loading was successful,
108 and resolve() to resolve a symbol in the library. The resolve()
109 function implicitly tries to load the library if it has not been
110 loaded yet. Multiple instances of QLibrary can be used to access
111 the same physical library. Once loaded, libraries remain in memory
112 until the application terminates. You can attempt to unload a
113 library using unload(), but if other instances of QLibrary are
114 using the same library, the call will fail, and unloading will
115 only happen when every instance has called unload().
116
117 A typical use of QLibrary is to resolve an exported symbol in a
118 library, and to call the C function that this symbol represents.
119 This is called "explicit linking" in contrast to "implicit
120 linking", which is done by the link step in the build process when
121 linking an executable against a library.
122
123 Note: In Symbian resolving symbols using their names is supported
124 only if the library is built as STDDLL. Otherwise ordinals must
125 be used. Also, in Symbian the path of the library is ignored and
126 system default library location is always used.
127
128 The following code snippet loads a library, resolves the symbol
129 "mysymbol", and calls the function if everything succeeded. If
130 something goes wrong, e.g. the library file does not exist or the
131 symbol is not defined, the function pointer will be 0 and won't be
132 called.
133
134 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 0
135
136 The symbol must be exported as a C function from the library for
137 resolve() to work. This means that the function must be wrapped in
138 an \c{extern "C"} block if the library is compiled with a C++
139 compiler. On Windows, this also requires the use of a \c dllexport
140 macro; see resolve() for the details of how this is done. For
141 convenience, there is a static resolve() function which you can
142 use if you just want to call a function in a library without
143 explicitly loading the library first:
144
145 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 1
146
147 \sa QPluginLoader
148 */
149
150 /*!
151 \enum QLibrary::LoadHint
152
153 This enum describes the possible hints that can be used to change the way
154 libraries are handled when they are loaded. These values indicate how
155 symbols are resolved when libraries are loaded, and are specified using
156 the setLoadHints() function.
157
158 \value ResolveAllSymbolsHint
159 Causes all symbols in a library to be resolved when it is loaded, not
160 simply when resolve() is called.
161 \value ExportExternalSymbolsHint
162 Exports unresolved and external symbols in the library so that they can be
163 resolved in other dynamically-loaded libraries loaded later.
164 \value LoadArchiveMemberHint
165 Allows the file name of the library to specify a particular object file
166 within an archive file.
167 If this hint is given, the filename of the library consists of
168 a path, which is a reference to an archive file, followed by
169 a reference to the archive member.
170
171 \sa loadHints
172 */
173
174
175 #ifndef QT_NO_PLUGIN_CHECK
176 struct qt_token_info
177 {
qt_token_infoqt_token_info178 qt_token_info(const char *f, const ulong fc)
179 : fields(f), field_count(fc), results(fc), lengths(fc)
180 {
181 results.fill(0);
182 lengths.fill(0);
183 }
184
185 const char *fields;
186 const ulong field_count;
187
188 QVector<const char *> results;
189 QVector<ulong> lengths;
190 };
191
192 /*
193 return values:
194 1 parse ok
195 0 eos
196 -1 parse error
197 */
qt_tokenize(const char * s,ulong s_len,ulong * advance,qt_token_info & token_info)198 static int qt_tokenize(const char *s, ulong s_len, ulong *advance,
199 qt_token_info &token_info)
200 {
201 if (!s)
202 return -1;
203
204 ulong pos = 0, field = 0, fieldlen = 0;
205 char current;
206 int ret = -1;
207 *advance = 0;
208 for (;;) {
209 current = s[pos];
210
211 // next char
212 ++pos;
213 ++fieldlen;
214 ++*advance;
215
216 if (! current || pos == s_len + 1) {
217 // save result
218 token_info.results[(int)field] = s;
219 token_info.lengths[(int)field] = fieldlen - 1;
220
221 // end of string
222 ret = 0;
223 break;
224 }
225
226 if (current == token_info.fields[field]) {
227 // save result
228 token_info.results[(int)field] = s;
229 token_info.lengths[(int)field] = fieldlen - 1;
230
231 // end of field
232 fieldlen = 0;
233 ++field;
234 if (field == token_info.field_count - 1) {
235 // parse ok
236 ret = 1;
237 }
238 if (field == token_info.field_count) {
239 // done parsing
240 break;
241 }
242
243 // reset string and its length
244 s = s + pos;
245 s_len -= pos;
246 pos = 0;
247 }
248 }
249
250 return ret;
251 }
252
253 /*
254 returns true if the string s was correctly parsed, false otherwise.
255 */
qt_parse_pattern(const char * s,uint * version,bool * debug,QByteArray * key)256 static bool qt_parse_pattern(const char *s, uint *version, bool *debug, QByteArray *key)
257 {
258 bool ret = true;
259
260 qt_token_info pinfo("=\n", 2);
261 int parse;
262 ulong at = 0, advance, parselen = qstrlen(s);
263 do {
264 parse = qt_tokenize(s + at, parselen, &advance, pinfo);
265 if (parse == -1) {
266 ret = false;
267 break;
268 }
269
270 at += advance;
271 parselen -= advance;
272
273 if (qstrncmp("version", pinfo.results[0], pinfo.lengths[0]) == 0) {
274 // parse version string
275 qt_token_info pinfo2("..-", 3);
276 if (qt_tokenize(pinfo.results[1], pinfo.lengths[1],
277 &advance, pinfo2) != -1) {
278 QByteArray m(pinfo2.results[0], pinfo2.lengths[0]);
279 QByteArray n(pinfo2.results[1], pinfo2.lengths[1]);
280 QByteArray p(pinfo2.results[2], pinfo2.lengths[2]);
281 *version = (m.toUInt() << 16) | (n.toUInt() << 8) | p.toUInt();
282 } else {
283 ret = false;
284 break;
285 }
286 } else if (qstrncmp("debug", pinfo.results[0], pinfo.lengths[0]) == 0) {
287 *debug = qstrncmp("true", pinfo.results[1], pinfo.lengths[1]) == 0;
288 } else if (qstrncmp("buildkey", pinfo.results[0],
289 pinfo.lengths[0]) == 0){
290 // save buildkey
291 *key = QByteArray(pinfo.results[1], pinfo.lengths[1]);
292 }
293 } while (parse == 1 && parselen > 0);
294
295 return ret;
296 }
297 #endif // QT_NO_PLUGIN_CHECK
298
299 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
300
qt_find_pattern(const char * s,ulong s_len,const char * pattern,ulong p_len)301 static long qt_find_pattern(const char *s, ulong s_len,
302 const char *pattern, ulong p_len)
303 {
304 /*
305 we search from the end of the file because on the supported
306 systems, the read-only data/text segments are placed at the end
307 of the file. HOWEVER, when building with debugging enabled, all
308 the debug symbols are placed AFTER the data/text segments.
309
310 what does this mean? when building in release mode, the search
311 is fast because the data we are looking for is at the end of the
312 file... when building in debug mode, the search is slower
313 because we have to skip over all the debugging symbols first
314 */
315
316 if (! s || ! pattern || p_len > s_len) return -1;
317 ulong i, hs = 0, hp = 0, delta = s_len - p_len;
318
319 for (i = 0; i < p_len; ++i) {
320 hs += s[delta + i];
321 hp += pattern[i];
322 }
323 i = delta;
324 for (;;) {
325 if (hs == hp && qstrncmp(s + i, pattern, p_len) == 0)
326 return i;
327 if (i == 0)
328 break;
329 --i;
330 hs -= s[i + p_len];
331 hs += s[i];
332 }
333
334 return -1;
335 }
336
337 /*
338 This opens the specified library, mmaps it into memory, and searches
339 for the QT_PLUGIN_VERIFICATION_DATA. The advantage of this approach is that
340 we can get the verification data without have to actually load the library.
341 This lets us detect mismatches more safely.
342
343 Returns false if version/key information is not present, or if the
344 information could not be read.
345 Returns true if version/key information is present and successfully read.
346 */
qt_unix_query(const QString & library,uint * version,bool * debug,QByteArray * key,QLibraryPrivate * lib=0)347 static bool qt_unix_query(const QString &library, uint *version, bool *debug, QByteArray *key, QLibraryPrivate *lib = 0)
348 {
349 QFile file(library);
350 if (!file.open(QIODevice::ReadOnly)) {
351 if (lib)
352 lib->errorString = file.errorString();
353 if (qt_debug_component()) {
354 qWarning("%s: %s", (const char*) QFile::encodeName(library),
355 qPrintable(qt_error_string(errno)));
356 }
357 return false;
358 }
359
360 QByteArray data;
361 const char *filedata = 0;
362 ulong fdlen = file.size();
363 filedata = (char *) file.map(0, fdlen);
364 if (filedata == 0) {
365 // try reading the data into memory instead
366 data = file.readAll();
367 filedata = data.constData();
368 fdlen = data.size();
369 }
370
371 /*
372 ELF binaries on GNU, have .qplugin sections.
373 */
374 long pos = 0;
375 const char pattern[] = "pattern=QT_PLUGIN_VERIFICATION_DATA";
376 const ulong plen = qstrlen(pattern);
377 #if defined (Q_OF_ELF) && defined(Q_CC_GNU)
378 int r = QElfParser().parse(filedata, fdlen, library, lib, &pos, &fdlen);
379 if (r == QElfParser::NoQtSection) {
380 if (pos > 0) {
381 // find inside .rodata
382 long rel = qt_find_pattern(filedata + pos, fdlen, pattern, plen);
383 if (rel < 0) {
384 pos = -1;
385 } else {
386 pos += rel;
387 }
388 } else {
389 pos = qt_find_pattern(filedata, fdlen, pattern, plen);
390 }
391 } else if (r != QElfParser::Ok) {
392 if (lib && qt_debug_component()) {
393 qWarning("QElfParser: %s",qPrintable(lib->errorString));
394 }
395 return false;
396 }
397 #else
398 pos = qt_find_pattern(filedata, fdlen, pattern, plen);
399 #endif // defined(Q_OF_ELF) && defined(Q_CC_GNU)
400 bool ret = false;
401 if (pos >= 0)
402 ret = qt_parse_pattern(filedata + pos, version, debug, key);
403
404 if (!ret && lib)
405 lib->errorString = QLibrary::tr("Plugin verification data mismatch in '%1'").arg(library);
406 file.close();
407 return ret;
408 }
409
410 #endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
411
412 typedef QMap<QString, QLibraryPrivate*> LibraryMap;
413
414 struct LibraryData {
415 LibraryMap libraryMap;
416 QSet<QLibraryPrivate*> loadedLibs;
417 };
418
Q_GLOBAL_STATIC(LibraryData,libraryData)419 Q_GLOBAL_STATIC(LibraryData, libraryData)
420
421 static LibraryMap *libraryMap()
422 {
423 LibraryData *data = libraryData();
424 return data ? &data->libraryMap : 0;
425 }
426
QLibraryPrivate(const QString & canonicalFileName,const QString & version)427 QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version)
428 :pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0), qt_version(0),
429 libraryRefCount(1), libraryUnloadCount(0), pluginState(MightBeAPlugin)
430 { libraryMap()->insert(canonicalFileName, this); }
431
findOrCreate(const QString & fileName,const QString & version)432 QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version)
433 {
434 QMutexLocker locker(qt_library_mutex());
435 if (QLibraryPrivate *lib = libraryMap()->value(fileName)) {
436 lib->libraryRefCount.ref();
437 return lib;
438 }
439
440 return new QLibraryPrivate(fileName, version);
441 }
442
~QLibraryPrivate()443 QLibraryPrivate::~QLibraryPrivate()
444 {
445 LibraryMap * const map = libraryMap();
446 if (map) {
447 QLibraryPrivate *that = map->take(fileName);
448 Q_ASSERT(this == that);
449 Q_UNUSED(that);
450 }
451 }
452
resolve(const char * symbol)453 void *QLibraryPrivate::resolve(const char *symbol)
454 {
455 if (!pHnd)
456 return 0;
457 return resolve_sys(symbol);
458 }
459
460
load()461 bool QLibraryPrivate::load()
462 {
463 libraryUnloadCount.ref();
464 if (pHnd)
465 return true;
466 if (fileName.isEmpty())
467 return false;
468
469 bool ret = load_sys();
470 if (ret) {
471 //when loading a library we add a reference to it so that the QLibraryPrivate won't get deleted
472 //this allows to unload the library at a later time
473 if (LibraryData *lib = libraryData()) {
474 lib->loadedLibs += this;
475 libraryRefCount.ref();
476 }
477 }
478
479 return ret;
480 }
481
unload()482 bool QLibraryPrivate::unload()
483 {
484 if (!pHnd)
485 return false;
486 if (!libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
487 delete inst.data();
488 if (unload_sys()) {
489 if (qt_debug_component())
490 qWarning() << "QLibraryPrivate::unload succeeded on" << fileName;
491 //when the library is unloaded, we release the reference on it so that 'this'
492 //can get deleted
493 if (LibraryData *lib = libraryData()) {
494 if (lib->loadedLibs.remove(this))
495 libraryRefCount.deref();
496 }
497 pHnd = 0;
498 }
499 }
500
501 return (pHnd == 0);
502 }
503
release()504 void QLibraryPrivate::release()
505 {
506 QMutexLocker locker(qt_library_mutex());
507 if (!libraryRefCount.deref())
508 delete this;
509 }
510
loadPlugin()511 bool QLibraryPrivate::loadPlugin()
512 {
513 if (instance) {
514 libraryUnloadCount.ref();
515 return true;
516 }
517 if (pluginState == IsNotAPlugin)
518 return false;
519 if (load()) {
520 instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance");
521 #if defined(Q_OS_SYMBIAN)
522 if (!instance) {
523 // If resolving with function name failed (i.e. not STDDLL),
524 // try resolving using known ordinal, which for
525 // qt_plugin_instance function is always "2".
526 instance = (QtPluginInstanceFunction)resolve("2");
527 }
528 #endif
529 return instance;
530 }
531 if (qt_debug_component())
532 qWarning() << "QLibraryPrivate::loadPlugin failed on" << fileName << ":" << errorString;
533 pluginState = IsNotAPlugin;
534 return false;
535 }
536
537 /*!
538 Returns true if \a fileName has a valid suffix for a loadable
539 library; otherwise returns false.
540
541 \table
542 \header \i Platform \i Valid suffixes
543 \row \i Windows \i \c .dll, \c .DLL
544 \row \i Unix/Linux \i \c .so
545 \row \i AIX \i \c .a
546 \row \i HP-UX \i \c .sl, \c .so (HP-UXi)
547 \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so
548 \row \i Symbian \i \c .dll
549 \endtable
550
551 Trailing versioning numbers on Unix are ignored.
552 */
isLibrary(const QString & fileName)553 bool QLibrary::isLibrary(const QString &fileName)
554 {
555 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
556 return fileName.endsWith(QLatin1String(".dll"), Qt::CaseInsensitive);
557 #elif defined(Q_OS_SYMBIAN)
558 // Plugin stubs are also considered libraries in Symbian.
559 return (fileName.endsWith(QLatin1String(".dll")) ||
560 fileName.endsWith(QLatin1String(".qtplugin")));
561 #else
562 QString completeSuffix = QFileInfo(fileName).completeSuffix();
563 if (completeSuffix.isEmpty())
564 return false;
565 QStringList suffixes = completeSuffix.split(QLatin1Char('.'));
566 # if defined(Q_OS_DARWIN)
567
568 // On Mac, libs look like libmylib.1.0.0.dylib
569 const QString lastSuffix = suffixes.at(suffixes.count() - 1);
570 const QString firstSuffix = suffixes.at(0);
571
572 bool valid = (lastSuffix == QLatin1String("dylib")
573 || firstSuffix == QLatin1String("so")
574 || firstSuffix == QLatin1String("bundle"));
575
576 return valid;
577 # else // Generic Unix
578 QStringList validSuffixList;
579
580 # if defined(Q_OS_HPUX)
581 /*
582 See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF":
583 "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit),
584 the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix."
585 */
586 validSuffixList << QLatin1String("sl");
587 # if defined __ia64
588 validSuffixList << QLatin1String("so");
589 # endif
590 # elif defined(Q_OS_AIX)
591 validSuffixList << QLatin1String("a") << QLatin1String("so");
592 # elif defined(Q_OS_UNIX)
593 validSuffixList << QLatin1String("so");
594 # endif
595
596 // Examples of valid library names:
597 // libfoo.so
598 // libfoo.so.0
599 // libfoo.so.0.3
600 // libfoo-0.3.so
601 // libfoo-0.3.so.0.3.0
602
603 int suffix;
604 int suffixPos = -1;
605 for (suffix = 0; suffix < validSuffixList.count() && suffixPos == -1; ++suffix)
606 suffixPos = suffixes.indexOf(validSuffixList.at(suffix));
607
608 bool valid = suffixPos != -1;
609 for (int i = suffixPos + 1; i < suffixes.count() && valid; ++i)
610 if (i != suffixPos)
611 suffixes.at(i).toInt(&valid);
612 return valid;
613 # endif
614 #endif
615
616 }
617
618 #if defined (Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_CC_INTEL)
619 #define QT_USE_MS_STD_EXCEPTION 1
qt_try_versioninfo(void * pfn,bool * exceptionThrown)620 const char* qt_try_versioninfo(void *pfn, bool *exceptionThrown)
621 {
622 *exceptionThrown = false;
623 const char *szData = 0;
624 typedef const char * (*VerificationFunction)();
625 VerificationFunction func = reinterpret_cast<VerificationFunction>(pfn);
626 __try {
627 if(func)
628 szData = func();
629 } __except(EXCEPTION_EXECUTE_HANDLER) {
630 *exceptionThrown = true;
631 }
632 return szData;
633 }
634 #endif
635
636 #ifdef Q_CC_BOR
637 typedef const char * __stdcall (*QtPluginQueryVerificationDataFunction)();
638 #else
639 typedef const char * (*QtPluginQueryVerificationDataFunction)();
640 #endif
641
qt_get_verificationdata(QtPluginQueryVerificationDataFunction pfn,uint * qt_version,bool * debug,QByteArray * key,bool * exceptionThrown)642 bool qt_get_verificationdata(QtPluginQueryVerificationDataFunction pfn, uint *qt_version, bool *debug, QByteArray *key, bool *exceptionThrown)
643 {
644 *exceptionThrown = false;
645 const char *szData = 0;
646 if (!pfn)
647 return false;
648 #ifdef QT_USE_MS_STD_EXCEPTION
649 szData = qt_try_versioninfo((void *)pfn, exceptionThrown);
650 if (*exceptionThrown)
651 return false;
652 #else
653 szData = pfn();
654 #endif
655
656 #ifdef QT_NO_PLUGIN_CHECK
657 return true;
658 #else
659 return qt_parse_pattern(szData, qt_version, debug, key);
660 #endif
661 }
662
isPlugin(QSettings * settings)663 bool QLibraryPrivate::isPlugin(QSettings *settings)
664 {
665 errorString.clear();
666 if (pluginState != MightBeAPlugin)
667 return pluginState == IsAPlugin;
668
669 #ifndef QT_NO_PLUGIN_CHECK
670 bool debug = !QLIBRARY_AS_DEBUG;
671 QByteArray key;
672 bool success = false;
673
674 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
675 if (fileName.endsWith(QLatin1String(".debug"))) {
676 // refuse to load a file that ends in .debug
677 // these are the debug symbols from the libraries
678 // the problem is that they are valid shared library files
679 // and dlopen is known to crash while opening them
680
681 // pretend we didn't see the file
682 errorString = QLibrary::tr("The shared library was not found.");
683 pluginState = IsNotAPlugin;
684 return false;
685 }
686 #endif
687
688 QFileInfo fileinfo(fileName);
689
690 #ifndef QT_NO_DATESTRING
691 lastModified = fileinfo.lastModified().toString(Qt::ISODate);
692 #endif
693 QString regkey = QString::fromLatin1("Qt Plugin Cache %1.%2.%3/%4")
694 .arg((QT_VERSION & 0xff0000) >> 16)
695 .arg((QT_VERSION & 0xff00) >> 8)
696 .arg(QLIBRARY_AS_DEBUG ? QLatin1String("debug") : QLatin1String("false"))
697 .arg(fileName);
698 #ifdef Q_WS_MAC
699 // On Mac, add the application arch to the reg key in order to
700 // cache plugin information separately for each arch. This prevents
701 // Qt from wrongly caching plugin load failures when the archs
702 // don't match.
703 #if defined(__x86_64__)
704 regkey += QLatin1String("-x86_64");
705 #elif defined(__i386__)
706 regkey += QLatin1String("-i386");
707 #elif defined(__ppc64__)
708 regkey += QLatin1String("-ppc64");
709 #elif defined(__ppc__)
710 regkey += QLatin1String("-ppc");
711 #endif
712 #endif // Q_WS_MAC
713
714 QStringList reg;
715 #ifndef QT_NO_SETTINGS
716 if (!settings) {
717 settings = QCoreApplicationPrivate::trolltechConf();
718 }
719 reg = settings->value(regkey).toStringList();
720 #endif
721 if (reg.count() == 4 && lastModified == reg.at(3)) {
722 qt_version = reg.at(0).toUInt(0, 16);
723 debug = bool(reg.at(1).toInt());
724 key = reg.at(2).toLatin1();
725 success = qt_version != 0;
726 } else {
727 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN)
728 if (!pHnd) {
729 // use unix shortcut to avoid loading the library
730 success = qt_unix_query(fileName, &qt_version, &debug, &key, this);
731 } else
732 #endif
733 {
734 bool retryLoadLibrary = false; // Only used on Windows with MS compiler.(false in other cases)
735 do {
736 bool temporary_load = false;
737 #ifdef Q_OS_WIN
738 HMODULE hTempModule = 0;
739 #endif
740 if (!pHnd) {
741 #ifdef Q_OS_WIN
742 DWORD dwFlags = (retryLoadLibrary) ? 0: DONT_RESOLVE_DLL_REFERENCES;
743 //avoid 'Bad Image' message box
744 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
745 hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, dwFlags);
746 SetErrorMode(oldmode);
747 #else
748 # if defined(Q_OS_SYMBIAN)
749 //Guard against accidentally trying to load non-plugin libraries by making sure the stub exists
750 if (fileinfo.exists())
751 # endif
752 temporary_load = load_sys();
753 #endif
754 }
755 #ifdef Q_OS_WIN
756 QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = hTempModule ? (QtPluginQueryVerificationDataFunction)
757 #ifdef Q_OS_WINCE
758 ::GetProcAddress(hTempModule, L"qt_plugin_query_verification_data")
759 #else
760 ::GetProcAddress(hTempModule, "qt_plugin_query_verification_data")
761 #endif
762 : (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
763 #else
764 QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL;
765 # if defined(Q_OS_SYMBIAN)
766 if (temporary_load) {
767 qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
768 // If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal
769 if (!qtPluginQueryVerificationDataFunction)
770 qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1");
771 }
772 # else
773 qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
774 # endif
775 #endif
776 bool exceptionThrown = false;
777 bool ret = qt_get_verificationdata(qtPluginQueryVerificationDataFunction,
778 &qt_version, &debug, &key, &exceptionThrown);
779 if (!exceptionThrown) {
780 if (!ret) {
781 qt_version = 0;
782 key = "unknown";
783 if (temporary_load)
784 unload_sys();
785 } else {
786 success = true;
787 }
788 retryLoadLibrary = false;
789 }
790 #ifdef QT_USE_MS_STD_EXCEPTION
791 else {
792 // An exception was thrown when calling qt_plugin_query_verification_data().
793 // This usually happens when plugin is compiled with the /clr compiler flag,
794 // & will only work if the dependencies are loaded & DLLMain() is called.
795 // LoadLibrary() will do this, try once with this & if it fails don't load.
796 retryLoadLibrary = !retryLoadLibrary;
797 }
798 #endif
799 #ifdef Q_OS_WIN
800 if (hTempModule) {
801 BOOL ok = ::FreeLibrary(hTempModule);
802 if (ok) {
803 hTempModule = 0;
804 }
805
806 }
807 #endif
808 } while(retryLoadLibrary); // Will be 'false' in all cases other than when an
809 // exception is thrown(will happen only when using a MS compiler)
810 }
811
812 // Qt 4.5 compatibility: stl doesn't affect binary compatibility
813 key.replace(" no-stl", "");
814
815 #ifndef QT_NO_SETTINGS
816 QStringList queried;
817 queried << QString::number(qt_version,16)
818 << QString::number((int)debug)
819 << QLatin1String(key)
820 << lastModified;
821 settings->setValue(regkey, queried);
822 #endif
823 }
824
825 if (!success) {
826 if (errorString.isEmpty()){
827 if (fileName.isEmpty())
828 errorString = QLibrary::tr("The shared library was not found.");
829 else
830 errorString = QLibrary::tr("The file '%1' is not a valid Qt plugin.").arg(fileName);
831 }
832 return false;
833 }
834
835 pluginState = IsNotAPlugin; // be pessimistic
836
837 if ((qt_version & 0x00ff00) > (QT_VERSION & 0x00ff00) || (qt_version & 0xff0000) != (QT_VERSION & 0xff0000)) {
838 if (qt_debug_component()) {
839 qWarning("In %s:\n"
840 " Plugin uses incompatible Qt library (%d.%d.%d) [%s]",
841 (const char*) QFile::encodeName(fileName),
842 (qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff,
843 debug ? "debug" : "release");
844 }
845 errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]")
846 .arg(fileName)
847 .arg((qt_version&0xff0000) >> 16)
848 .arg((qt_version&0xff00) >> 8)
849 .arg(qt_version&0xff)
850 .arg(debug ? QLatin1String("debug") : QLatin1String("release"));
851 } else if (key != QT_BUILD_KEY
852 // we may have some compatibility keys, try them too:
853 #ifdef QT_BUILD_KEY_COMPAT
854 && key != QT_BUILD_KEY_COMPAT
855 #endif
856 #ifdef QT_BUILD_KEY_COMPAT2
857 && key != QT_BUILD_KEY_COMPAT2
858 #endif
859 #ifdef QT_BUILD_KEY_COMPAT3
860 && key != QT_BUILD_KEY_COMPAT3
861 #endif
862 ) {
863 if (qt_debug_component()) {
864 qWarning("In %s:\n"
865 " Plugin uses incompatible Qt library\n"
866 " expected build key \"%s\", got \"%s\"",
867 (const char*) QFile::encodeName(fileName),
868 QT_BUILD_KEY,
869 key.isEmpty() ? "<null>" : (const char *) key);
870 }
871 errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library."
872 " Expected build key \"%2\", got \"%3\"")
873 .arg(fileName)
874 .arg(QLatin1String(QT_BUILD_KEY))
875 .arg(key.isEmpty() ? QLatin1String("<null>") : QLatin1String((const char *) key));
876 #ifndef QT_NO_DEBUG_PLUGIN_CHECK
877 } else if(debug != QLIBRARY_AS_DEBUG) {
878 //don't issue a qWarning since we will hopefully find a non-debug? --Sam
879 errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library."
880 " (Cannot mix debug and release libraries.)").arg(fileName);
881 #endif
882 } else {
883 pluginState = IsAPlugin;
884 }
885
886 return pluginState == IsAPlugin;
887 #else
888 Q_UNUSED(settings);
889 return pluginState == MightBeAPlugin;
890 #endif
891 }
892
893 /*!
894 Loads the library and returns true if the library was loaded
895 successfully; otherwise returns false. Since resolve() always
896 calls this function before resolving any symbols it is not
897 necessary to call it explicitly. In some situations you might want
898 the library loaded in advance, in which case you would use this
899 function.
900
901 \sa unload()
902 */
load()903 bool QLibrary::load()
904 {
905 if (!d)
906 return false;
907 if (did_load)
908 return d->pHnd;
909 did_load = true;
910 return d->load();
911 }
912
913 /*!
914 Unloads the library and returns true if the library could be
915 unloaded; otherwise returns false.
916
917 This happens automatically on application termination, so you
918 shouldn't normally need to call this function.
919
920 If other instances of QLibrary are using the same library, the
921 call will fail, and unloading will only happen when every instance
922 has called unload().
923
924 Note that on Mac OS X 10.3 (Panther), dynamic libraries cannot be unloaded.
925
926 \sa resolve(), load()
927 */
unload()928 bool QLibrary::unload()
929 {
930 if (did_load) {
931 did_load = false;
932 return d->unload();
933 }
934 return false;
935 }
936
937 /*!
938 Returns true if the library is loaded; otherwise returns false.
939
940 \sa load()
941 */
isLoaded() const942 bool QLibrary::isLoaded() const
943 {
944 return d && d->pHnd;
945 }
946
947
948 /*!
949 Constructs a library with the given \a parent.
950 */
QLibrary(QObject * parent)951 QLibrary::QLibrary(QObject *parent)
952 :QObject(parent), d(0), did_load(false)
953 {
954 }
955
956
957 /*!
958 Constructs a library object with the given \a parent that will
959 load the library specified by \a fileName.
960
961 We recommend omitting the file's suffix in \a fileName, since
962 QLibrary will automatically look for the file with the appropriate
963 suffix in accordance with the platform, e.g. ".so" on Unix,
964 ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
965
966 Note: In Symbian the path portion of the \a fileName is ignored.
967 */
QLibrary(const QString & fileName,QObject * parent)968 QLibrary::QLibrary(const QString& fileName, QObject *parent)
969 :QObject(parent), d(0), did_load(false)
970 {
971 setFileName(fileName);
972 }
973
974
975 /*!
976 Constructs a library object with the given \a parent that will
977 load the library specified by \a fileName and major version number \a verNum.
978 Currently, the version number is ignored on Windows and Symbian.
979
980 We recommend omitting the file's suffix in \a fileName, since
981 QLibrary will automatically look for the file with the appropriate
982 suffix in accordance with the platform, e.g. ".so" on Unix,
983 ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
984
985 Note: In Symbian the path portion of the \a fileName is ignored.
986 */
QLibrary(const QString & fileName,int verNum,QObject * parent)987 QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent)
988 :QObject(parent), d(0), did_load(false)
989 {
990 setFileNameAndVersion(fileName, verNum);
991 }
992
993 /*!
994 Constructs a library object with the given \a parent that will
995 load the library specified by \a fileName and full version number \a version.
996 Currently, the version number is ignored on Windows and Symbian.
997
998 We recommend omitting the file's suffix in \a fileName, since
999 QLibrary will automatically look for the file with the appropriate
1000 suffix in accordance with the platform, e.g. ".so" on Unix,
1001 ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
1002
1003 Note: In Symbian the path portion of the \a fileName is ignored.
1004 */
QLibrary(const QString & fileName,const QString & version,QObject * parent)1005 QLibrary::QLibrary(const QString& fileName, const QString &version, QObject *parent)
1006 :QObject(parent), d(0), did_load(false)
1007 {
1008 setFileNameAndVersion(fileName, version);
1009 }
1010
1011 /*!
1012 Destroys the QLibrary object.
1013
1014 Unless unload() was called explicitly, the library stays in memory
1015 until the application terminates.
1016
1017 \sa isLoaded(), unload()
1018 */
~QLibrary()1019 QLibrary::~QLibrary()
1020 {
1021 if (d)
1022 d->release();
1023 }
1024
1025
1026 /*!
1027 \property QLibrary::fileName
1028 \brief the file name of the library
1029
1030 We recommend omitting the file's suffix in the file name, since
1031 QLibrary will automatically look for the file with the appropriate
1032 suffix (see isLibrary()).
1033
1034 When loading the library, QLibrary searches in all system-specific
1035 library locations (e.g. \c LD_LIBRARY_PATH on Unix), unless the
1036 file name has an absolute path. After loading the library
1037 successfully, fileName() returns the fully-qualified file name of
1038 the library, including the full path to the library if one was given
1039 in the constructor or passed to setFileName().
1040
1041 For example, after successfully loading the "GL" library on Unix
1042 platforms, fileName() will return "libGL.so". If the file name was
1043 originally passed as "/usr/lib/libGL", fileName() will return
1044 "/usr/lib/libGL.so".
1045
1046 Note: In Symbian the path portion of the \a fileName is ignored.
1047 */
1048
setFileName(const QString & fileName)1049 void QLibrary::setFileName(const QString &fileName)
1050 {
1051 QLibrary::LoadHints lh;
1052 if (d) {
1053 lh = d->loadHints;
1054 d->release();
1055 d = 0;
1056 did_load = false;
1057 }
1058 d = QLibraryPrivate::findOrCreate(fileName);
1059 d->loadHints = lh;
1060 }
1061
fileName() const1062 QString QLibrary::fileName() const
1063 {
1064 if (d)
1065 return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
1066 return QString();
1067 }
1068
1069 /*!
1070 \fn void QLibrary::setFileNameAndVersion(const QString &fileName, int versionNumber)
1071
1072 Sets the fileName property and major version number to \a fileName
1073 and \a versionNumber respectively.
1074 The \a versionNumber is ignored on Windows and Symbian.
1075
1076 Note: In Symbian the path portion of the \a fileName is ignored.
1077
1078 \sa setFileName()
1079 */
setFileNameAndVersion(const QString & fileName,int verNum)1080 void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum)
1081 {
1082 QLibrary::LoadHints lh;
1083 if (d) {
1084 lh = d->loadHints;
1085 d->release();
1086 d = 0;
1087 did_load = false;
1088 }
1089 d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString());
1090 d->loadHints = lh;
1091 }
1092
1093 /*!
1094 \since 4.4
1095
1096 Sets the fileName property and full version number to \a fileName
1097 and \a version respectively.
1098 The \a version parameter is ignored on Windows and Symbian.
1099
1100 Note: In Symbian the path portion of the \a fileName is ignored.
1101
1102 \sa setFileName()
1103 */
setFileNameAndVersion(const QString & fileName,const QString & version)1104 void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &version)
1105 {
1106 QLibrary::LoadHints lh;
1107 if (d) {
1108 lh = d->loadHints;
1109 d->release();
1110 d = 0;
1111 did_load = false;
1112 }
1113 d = QLibraryPrivate::findOrCreate(fileName, version);
1114 d->loadHints = lh;
1115 }
1116
1117 /*!
1118 Returns the address of the exported symbol \a symbol. The library is
1119 loaded if necessary. The function returns 0 if the symbol could
1120 not be resolved or if the library could not be loaded.
1121
1122 Example:
1123 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 2
1124
1125 The symbol must be exported as a C function from the library. This
1126 means that the function must be wrapped in an \c{extern "C"} if
1127 the library is compiled with a C++ compiler. On Windows you must
1128 also explicitly export the function from the DLL using the
1129 \c{__declspec(dllexport)} compiler directive, for example:
1130
1131 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 3
1132
1133 with \c MY_EXPORT defined as
1134
1135 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 4
1136
1137 Note: In Symbian resolving with symbol names works only if the loaded
1138 library was built as STDDLL. Otherwise, the ordinals must be used.
1139 */
resolve(const char * symbol)1140 void *QLibrary::resolve(const char *symbol)
1141 {
1142 if (!isLoaded() && !load())
1143 return 0;
1144 return d->resolve(symbol);
1145 }
1146
1147 /*!
1148 \overload
1149
1150 Loads the library \a fileName and returns the address of the
1151 exported symbol \a symbol. Note that \a fileName should not
1152 include the platform-specific file suffix; (see \l{fileName}). The
1153 library remains loaded until the application exits.
1154
1155 The function returns 0 if the symbol could not be resolved or if
1156 the library could not be loaded.
1157
1158 Note: In Symbian resolving with symbol names works only if the loaded
1159 library was built as STDDLL. Otherwise, the ordinals must be used.
1160
1161 \sa resolve()
1162 */
resolve(const QString & fileName,const char * symbol)1163 void *QLibrary::resolve(const QString &fileName, const char *symbol)
1164 {
1165 QLibrary library(fileName);
1166 return library.resolve(symbol);
1167 }
1168
1169 /*!
1170 \overload
1171
1172 Loads the library \a fileName with major version number \a verNum and
1173 returns the address of the exported symbol \a symbol.
1174 Note that \a fileName should not include the platform-specific file suffix;
1175 (see \l{fileName}). The library remains loaded until the application exits.
1176 \a verNum is ignored on Windows.
1177
1178 The function returns 0 if the symbol could not be resolved or if
1179 the library could not be loaded.
1180
1181 Note: In Symbian resolving with symbol names works only if the loaded
1182 library was built as STDDLL. Otherwise, the ordinals must be used.
1183
1184 \sa resolve()
1185 */
resolve(const QString & fileName,int verNum,const char * symbol)1186 void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
1187 {
1188 QLibrary library(fileName, verNum);
1189 return library.resolve(symbol);
1190 }
1191
1192 /*!
1193 \overload
1194 \since 4.4
1195
1196 Loads the library \a fileName with full version number \a version and
1197 returns the address of the exported symbol \a symbol.
1198 Note that \a fileName should not include the platform-specific file suffix;
1199 (see \l{fileName}). The library remains loaded until the application exits.
1200 \a version is ignored on Windows.
1201
1202 The function returns 0 if the symbol could not be resolved or if
1203 the library could not be loaded.
1204
1205 Note: In Symbian resolving with symbol names works only if the loaded
1206 library was built as STDDLL. Otherwise, the ordinals must be used.
1207
1208 \sa resolve()
1209 */
resolve(const QString & fileName,const QString & version,const char * symbol)1210 void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol)
1211 {
1212 QLibrary library(fileName, version);
1213 return library.resolve(symbol);
1214 }
1215
1216 /*!
1217 \fn QString QLibrary::library() const
1218
1219 Use fileName() instead.
1220 */
1221
1222 /*!
1223 \fn void QLibrary::setAutoUnload( bool b )
1224
1225 Use load(), isLoaded(), and unload() as necessary instead.
1226 */
1227
1228 /*!
1229 \since 4.2
1230
1231 Returns a text string with the description of the last error that occurred.
1232 Currently, errorString will only be set if load(), unload() or resolve() for some reason fails.
1233 */
errorString() const1234 QString QLibrary::errorString() const
1235 {
1236 return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
1237 }
1238
1239 /*!
1240 \property QLibrary::loadHints
1241 \brief Give the load() function some hints on how it should behave.
1242
1243 You can give some hints on how the symbols are resolved. Usually,
1244 the symbols are not resolved at load time, but resolved lazily,
1245 (that is, when resolve() is called). If you set the loadHint to
1246 ResolveAllSymbolsHint, then all symbols will be resolved at load time
1247 if the platform supports it.
1248
1249 Setting ExportExternalSymbolsHint will make the external symbols in the
1250 library available for resolution in subsequent loaded libraries.
1251
1252 If LoadArchiveMemberHint is set, the file name
1253 is composed of two components: A path which is a reference to an
1254 archive file followed by the second component which is the reference to
1255 the archive member. For instance, the fileName \c libGL.a(shr_64.o) will refer
1256 to the library \c shr_64.o in the archive file named \c libGL.a. This
1257 is only supported on the AIX platform.
1258
1259 The interpretation of the load hints is platform dependent, and if
1260 you use it you are probably making some assumptions on which platform
1261 you are compiling for, so use them only if you understand the consequences
1262 of them.
1263
1264 By default, none of these flags are set, so libraries will be loaded with
1265 lazy symbol resolution, and will not export external symbols for resolution
1266 in other dynamically-loaded libraries.
1267 */
setLoadHints(LoadHints hints)1268 void QLibrary::setLoadHints(LoadHints hints)
1269 {
1270 if (!d) {
1271 d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
1272 d->errorString.clear();
1273 }
1274 d->loadHints = hints;
1275 }
1276
loadHints() const1277 QLibrary::LoadHints QLibrary::loadHints() const
1278 {
1279 return d ? d->loadHints : (QLibrary::LoadHints)0;
1280 }
1281
1282 /* Internal, for debugging */
qt_debug_component()1283 bool qt_debug_component()
1284 {
1285 static int debug_env = -1;
1286 if (debug_env == -1)
1287 debug_env = QT_PREPEND_NAMESPACE(qgetenv)("QT_DEBUG_PLUGINS").toInt();
1288
1289 return debug_env != 0;
1290 }
1291
1292 QT_END_NAMESPACE
1293
1294 #endif // QT_NO_LIBRARY
1295