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