From 46c73be4710a6aa1be84a19151f73d87413a52b4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 30 Jan 2016 09:48:41 -0800 Subject: Fix livelock at application exit if threads were running This only happened in debug mode, though, because in release mode the warning wasn't printed and the socket notifier was removed. In debug mode, this loop in closingDown() never exited: while (!d->sn_read.isEmpty()) unregisterSocketNotifier((*(d->sn_read.begin()))->obj); [ChangeLog][QtCore][QThread] Fixed a bug that would cause debug-mode applications to live lock on exit if they had a global static containing a QThread that wasn't properly exited. Task-number: QTBUG-49870 Change-Id: I7a9e11d7b64a4cc78e24ffff142e457a4540d6b6 Reviewed-by: Mat Sutcliffe Reviewed-by: Roland Winklmeier Reviewed-by: Friedemann Kleint --- src/corelib/kernel/qeventdispatcher_win.cpp | 17 ++++++++++++----- src/corelib/kernel/qeventdispatcher_win_p.h | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 1a14500bd4..b3df139743 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -935,9 +935,8 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier) void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) { Q_ASSERT(notifier); - int sockfd = notifier->socket(); - int type = notifier->type(); #ifndef QT_NO_DEBUG + int sockfd = notifier->socket(); if (sockfd < 0) { qWarning("QSocketNotifier: Internal error"); return; @@ -946,8 +945,16 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) return; } #endif + doUnregisterSocketNotifier(notifier); +} +void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier) +{ Q_D(QEventDispatcherWin32); + int type = notifier->type(); + int sockfd = notifier->socket(); + Q_ASSERT(sockfd >= 0); + QSFDict::iterator it = d->active_fd.find(sockfd); if (it != d->active_fd.end()) { QSockFd &sd = it.value(); @@ -1203,11 +1210,11 @@ void QEventDispatcherWin32::closingDown() // clean up any socketnotifiers while (!d->sn_read.isEmpty()) - unregisterSocketNotifier((*(d->sn_read.begin()))->obj); + doUnregisterSocketNotifier((*(d->sn_read.begin()))->obj); while (!d->sn_write.isEmpty()) - unregisterSocketNotifier((*(d->sn_write.begin()))->obj); + doUnregisterSocketNotifier((*(d->sn_write.begin()))->obj); while (!d->sn_except.isEmpty()) - unregisterSocketNotifier((*(d->sn_except.begin()))->obj); + doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj); Q_ASSERT(d->active_fd.isEmpty()); // clean up any timers diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index 9a53e06730..222562dfce 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -103,6 +103,7 @@ public: protected: QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = 0); virtual void sendPostedEvents(); + void doUnregisterSocketNotifier(QSocketNotifier *notifier); private: friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); -- cgit v1.2.3 From 3726c46735edb23ad37af818ff7d52d661ec87e7 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 29 Jan 2016 13:41:38 -0800 Subject: Work around Clang < 3.7 integrated assembler bug PC-relative relocs The qversiontagging.h inline assembly expands to: .long qt_version_tag@GOTPCREL Which, with GCC, Clang >= 3.7 and with the option -no-integrated-as in previous versions, produces the proper relocation (a R_X86_64_GOTPCREL). With Clang < 3.7, it instead produces a R_X86_64_32, which is unsuitable for use in shared libraries: 32-bit displacement is insufficiently wide and would produce linker errors like obj/qftp.o: requires dynamic R_X86_64_32 reloc against 'qt_version_tag' which may overflow at runtime; recompile with -fPIC Instead, force a 64-bit relocation (an R_X86_64_GOT64), which like the 32-bit version is simply an offset into the GOT of where the address of the symbol is stored. Task-number: QTBUG-50749 Change-Id: I7a9e11d7b64a4cc78e24ffff142e039c172b802c Reviewed-by: Simon Hausmann --- src/corelib/global/qversiontagging.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/global/qversiontagging.h b/src/corelib/global/qversiontagging.h index d6b4a65600..953f669501 100644 --- a/src/corelib/global/qversiontagging.h +++ b/src/corelib/global/qversiontagging.h @@ -59,11 +59,7 @@ QT_BEGIN_NAMESPACE #elif defined(Q_CC_GNU) && !defined(Q_OS_ANDROID) # if defined(Q_PROCESSOR_X86) && (defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD_KERNEL)) # if defined(Q_PROCESSOR_X86_64) // x86-64 or x32 -# if defined(__code_model_large__) -# define QT_VERSION_TAG_RELOC(sym) ".quad " QT_STRINGIFY(QT_MANGLE_NAMESPACE(sym)) "@GOT\n" -# else -# define QT_VERSION_TAG_RELOC(sym) ".long " QT_STRINGIFY(QT_MANGLE_NAMESPACE(sym)) "@GOTPCREL\n" -# endif +# define QT_VERSION_TAG_RELOC(sym) ".quad " QT_STRINGIFY(QT_MANGLE_NAMESPACE(sym)) "@GOT\n" # else // x86 # define QT_VERSION_TAG_RELOC(sym) ".long " QT_STRINGIFY(QT_MANGLE_NAMESPACE(sym)) "@GOT\n" # endif -- cgit v1.2.3 From ccf74b592809e0c5a613eff27d6431a4c659e368 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 29 Jan 2016 13:27:53 -0800 Subject: Fix build on FreeBSD: 'environ' is not defined in a library On FreeBSD, this variable is defined as a common symbol in the object file /usr/lib/crt1.o, which is injected into the final application by the compiler. This means when linking any library, 'environ' cannot be found and we can't use -Wl,-no-undefined on FreeBSD. I don't know why this wasn't caught before. Most likely, we failed to pass the linker flag until some recent change to the buildsystem. qprocess_unix.cpp:279: undefined reference to `environ' Change-Id: I7a9e11d7b64a4cc78e24ffff142e02dbf188bca5 Reviewed-by: Simon Hausmann Reviewed-by: Oswald Buddenhagen --- src/corelib/corelib.pro | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index 5cd0bde87b..ab3f29e2c7 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -27,6 +27,10 @@ ANDROID_PERMISSIONS = \ android.permission.INTERNET \ android.permission.WRITE_EXTERNAL_STORAGE +# QtCore can't be compiled with -Wl,-no-undefined because it uses the "environ" +# variable and on FreeBSD, this variable is in the final executable itself +freebsd: QMAKE_LFLAGS_NOUNDEF = + load(qt_module) load(qfeatures) -- cgit v1.2.3 From 38e602d0f2e4c292296d603fda22b366d8879daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Tue, 26 Jan 2016 13:46:28 +0100 Subject: Fix QT_DEPRECATED_SINCE usage The deprecation was introduced in 5.6 Change-Id: Ief6b749b40ec75c3c9f904caed8447bfb5ef5439 Reviewed-by: Marc Mutz Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/tools/qshareddata.h | 2 +- src/corelib/tools/qsharedpointer_impl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 6a0900cf3f..bc81135d7a 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -36,7 +36,7 @@ #include #include -#if QT_DEPRECATED_SINCE(5, 5) +#if QT_DEPRECATED_SINCE(5, 6) #include #endif #include diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index bd98cb326c..70b100d018 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -55,7 +55,7 @@ QT_END_NAMESPACE #include #include #include // for qobject_cast -#if QT_DEPRECATED_SINCE(5, 5) +#if QT_DEPRECATED_SINCE(5, 6) #include #endif #include -- cgit v1.2.3 From 448e9fdb57f6a7f7c2ad3986231039f21b20f854 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 2 Feb 2016 12:57:21 +0100 Subject: Enable NRVO in QJsonObject::keys() ... for poor compilers (such as GCC). The test (!d) was changed to match what other member functions test for, e.g. toVariantHash(). Change-Id: I85aee0df6e50da3623ad0afce24abb586e0bd1bc Reviewed-by: Lars Knoll --- src/corelib/json/qjsonobject.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp index 27f937e750..e43d811157 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/json/qjsonobject.cpp @@ -270,16 +270,14 @@ QVariantHash QJsonObject::toVariantHash() const */ QStringList QJsonObject::keys() const { - if (!d) - return QStringList(); - QStringList keys; - keys.reserve(o->length); - for (uint i = 0; i < o->length; ++i) { - QJsonPrivate::Entry *e = o->entryAt(i); - keys.append(e->key()); + if (o) { + keys.reserve(o->length); + for (uint i = 0; i < o->length; ++i) { + QJsonPrivate::Entry *e = o->entryAt(i); + keys.append(e->key()); + } } - return keys; } -- cgit v1.2.3 From 3cf4c492c2f8cf9f13f9e171b2f3fa6cbb2303f9 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 29 Jan 2016 16:07:24 +0100 Subject: Document QWinOverlappedIoNotifier restrictions Change-Id: I13cd14c29ddaf4c7423d672b0551081f87d8726b Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwinoverlappedionotifier.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp index 0cefa374fa..dee263c664 100644 --- a/src/corelib/io/qwinoverlappedionotifier.cpp +++ b/src/corelib/io/qwinoverlappedionotifier.cpp @@ -75,6 +75,22 @@ QT_BEGIN_NAMESPACE or WriteFile() is ignored and can be used for other purposes. \warning This class is only available on Windows. + + Due to peculiarities of the Windows I/O completion port API, users of + QWinOverlappedIoNotifier must pay attention to the following restrictions: + \list + \li File handles with a QWinOverlappedIoNotifer are assigned to an I/O + completion port until the handle is closed. It is impossible to + disassociate the file handle from the I/O completion port. + \li There can be only one QWinOverlappedIoNotifer per file handle. Creating + another QWinOverlappedIoNotifier for that file, even with a duplicated + handle, will fail. + \li Certain Windows API functions are unavailable for file handles that are + assigned to an I/O completion port. This includes the functions + \c{ReadFileEx} and \c{WriteFileEx}. + \endlist + See also the remarks in the MSDN documentation for the + \c{CreateIoCompletionPort} function. */ struct IOResult -- cgit v1.2.3 From 707068bd663c68e8d4716dbb46d1fcca13c6dcf2 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 9 Apr 2015 16:21:37 +0200 Subject: Remove Windows CE build hacks from QWindowsPipeWriter Those were added in ancient times to make QWindowsPipeWriter compile on Windows CE. It was never used though. Change-Id: Ica71b182f7ee4e47d9e33638d78475842b2ecdff Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipewriter.cpp | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index fd14523d45..21df5d0643 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -43,13 +43,8 @@ QWindowsPipeWriter::QWindowsPipeWriter(HANDLE pipe, QObject * parent) quitNow(false), hasWritten(false) { -#if !defined(Q_OS_WINCE) || (_WIN32_WCE >= 0x600) DuplicateHandle(GetCurrentProcess(), pipe, GetCurrentProcess(), &writePipe, 0, FALSE, DUPLICATE_SAME_ACCESS); -#else - Q_UNUSED(pipe); - writePipe = GetCurrentProcess(); -#endif } QWindowsPipeWriter::~QWindowsPipeWriter() @@ -60,9 +55,7 @@ QWindowsPipeWriter::~QWindowsPipeWriter() lock.unlock(); if (!wait(30000)) terminate(); -#if !defined(Q_OS_WINCE) || (_WIN32_WCE >= 0x600) CloseHandle(writePipe); -#endif } bool QWindowsPipeWriter::waitForWrite(int msecs) @@ -153,7 +146,6 @@ void QWindowsPipeWriter::run() msleep(100); continue; } -#ifndef Q_OS_WINCE if (writeError != ERROR_IO_PENDING) { qErrnoWarning(writeError, "QWindowsPipeWriter: async WriteFile failed."); return; @@ -162,9 +154,6 @@ void QWindowsPipeWriter::run() qErrnoWarning(GetLastError(), "QWindowsPipeWriter: GetOverlappedResult failed."); return; } -#else - return; -#endif } totalWritten += written; #if defined QPIPEWRITER_DEBUG -- cgit v1.2.3 From 70fb36e4bdefa37cff77decac5d549368e805aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Sun, 7 Feb 2016 01:39:37 +0000 Subject: docs: State that QMap::equal_range() returns an open-ended interval Change-Id: If31dd078aeb92e479db8c1f0a5e58e56b549b5f6 Reviewed-by: Martin Smith Reviewed-by: Marc Mutz --- src/corelib/tools/qmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index e49a1a098d..27ae07441e 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -1175,7 +1175,7 @@ void QMapDataBase::freeData(QMapDataBase *d) /*! \fn QPair QMap::equal_range(const Key &key) - Returns a pair of iterators delimiting the range of values that + Returns a pair of iterators delimiting the range of values \c{[first, second)}, that are stored under \a key. */ -- cgit v1.2.3 From c689bcafd3196aad22372e8056fe0ccb13c15f35 Mon Sep 17 00:00:00 2001 From: Heiko Becker Date: Fri, 12 Feb 2016 12:37:15 +0100 Subject: Search for libsystemd first, fall back to libsystemd-journal systemd >= 209 merged the individual libraries libsystemd-journal, libsystemd-login, libsystemd-id128 and libsystemd-daemon into a single library, libsystemd. To ease the transition one could pass an option to its build to generate stub libraries and matching pkg-config files. With systemd >= 229 this option has now been removed, causing the build to fail when the journald option is enabled. Change-Id: I26670f207f1a9e79c16be5ce8c8a49353143c5ba Reviewed-by: Oswald Buddenhagen Reviewed-by: Robin Burchell --- src/corelib/global/global.pri | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/corelib') diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index aa4945f90e..dd846955f6 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -53,7 +53,10 @@ slog2 { journald { CONFIG += link_pkgconfig - PKGCONFIG_PRIVATE += libsystemd-journal + packagesExist(libsystemd): \ + PKGCONFIG_PRIVATE += libsystemd + else: \ + PKGCONFIG_PRIVATE += libsystemd-journal DEFINES += QT_USE_JOURNALD } -- cgit v1.2.3 From 018e670a26ff5a61b949100ae080f5e654e7bee8 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Mon, 4 Jan 2016 17:56:05 +0100 Subject: OS X: Implement download folder display name query Up to now, the download folder display name was queried using FSFindFolder and kDesktopFolderType. Now that NSFileManager can be used unconditionnaly, the query has been replaced to use NSFileManager. [ChangeLog][QtCore][OS X] QStandardPaths now returns the correct display name for the download folder. Task-number: QTBUG-50262 Change-Id: Ie16c8daea3261a4dd5ca051956fc08d51656e0fa Reviewed-by: Jake Petroules --- src/corelib/io/qstandardpaths_mac.mm | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/io/qstandardpaths_mac.mm b/src/corelib/io/qstandardpaths_mac.mm index 7b97a03db2..f65ca2048a 100644 --- a/src/corelib/io/qstandardpaths_mac.mm +++ b/src/corelib/io/qstandardpaths_mac.mm @@ -229,6 +229,14 @@ QString QStandardPaths::displayName(StandardLocation type) if (QStandardPaths::HomeLocation == type) return QCoreApplication::translate("QStandardPaths", "Home"); + if (QStandardPaths::DownloadLocation == type) { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *url = [fileManager URLForDirectory:NSDownloadsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; + if (!url) + return QString(); + return QString::fromNSString([fileManager displayNameAtPath: [url absoluteString]]); + } + FSRef ref; OSErr err = FSFindFolder(kOnAppropriateDisk, translateLocation(type), false, &ref); if (err) -- cgit v1.2.3 From de82352d288475093a7692d8d998e8d6e9769e0e Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Sun, 14 Feb 2016 02:00:39 -0800 Subject: Wrap legacy APIs in a QT_MAC_DEPLOYMENT_TARGET_BELOW macro. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the deployment target is OS X >= 10.10 or iOS >= 8.0, we always have the NSProcessInfo API available and do not need to compile-in this code at all. Change-Id: I8470a5be475a82e7b88d62f4558925f62527b6f6 Reviewed-by: Tor Arne Vestbø --- src/corelib/kernel/qcore_mac_objc.mm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index 798307f8ab..1a2b047041 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -107,6 +107,7 @@ QAppleOperatingSystemVersion qt_apple_os_version() // Use temporary variables so we can return 0.0.0 (unknown version) // in case of an error partway through determining the OS version qint32 major = 0, minor = 0, patch = 0; +#if QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_10_10, __IPHONE_8_0) #if defined(Q_OS_IOS) @autoreleasepool { NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."]; @@ -129,6 +130,7 @@ QAppleOperatingSystemVersion qt_apple_os_version() return v; if (pGestalt('sys3', &patch) != 0) return v; +#endif #endif v.major = major; v.minor = minor; -- cgit v1.2.3 From 03f1a69e9cffe919597373471f7609521a465470 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 18 Mar 2015 08:49:39 +0100 Subject: Avoid size overflows when inserting into very large JSON objects QJson has a size limitation for arrays and objects. Make sure we don't go over that size limit and create corrupt objects when inserting data. Change-Id: I45be3caefc282d8041f38acd120b985ed4389b8c Reviewed-by: Oswald Buddenhagen Reviewed-by: Simon Hausmann Reviewed-by: Thiago Macieira --- src/corelib/json/qjson_p.h | 6 +++++- src/corelib/json/qjsonarray.cpp | 31 +++++++++++++++++++++++++------ src/corelib/json/qjsonarray.h | 6 ++++-- src/corelib/json/qjsondocument.cpp | 4 ++-- src/corelib/json/qjsonobject.cpp | 29 ++++++++++++++++++++++------- src/corelib/json/qjsonobject.h | 6 ++++-- 6 files changed, 62 insertions(+), 20 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h index 7f5a2d88a1..1767b3e9e6 100644 --- a/src/corelib/json/qjson_p.h +++ b/src/corelib/json/qjson_p.h @@ -788,7 +788,11 @@ public: if (reserve) { if (reserve < 128) reserve = 128; - size = qMax(size + reserve, size *2); + size = qMax(size + reserve, qMin(size *2, (int)Value::MaxSize)); + if (size > Value::MaxSize) { + qWarning("QJson: Document too large to store in data structure"); + return 0; + } } char *raw = (char *)malloc(size); Q_CHECK_PTR(raw); diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp index bb33dbde74..e8d54b5b87 100644 --- a/src/corelib/json/qjsonarray.cpp +++ b/src/corelib/json/qjsonarray.cpp @@ -382,7 +382,7 @@ void QJsonArray::removeAt(int i) if (!a || i < 0 || i >= (int)a->length) return; - detach(); + detach2(); a->removeItems(i, 1); ++d->compactionCounter; if (d->compactionCounter > 32u && d->compactionCounter >= unsigned(a->length) / 2u) @@ -442,7 +442,8 @@ void QJsonArray::insert(int i, const QJsonValue &value) bool compressed; int valueSize = QJsonPrivate::Value::requiredStorage(val, &compressed); - detach(valueSize + sizeof(QJsonPrivate::Value)); + if (!detach2(valueSize + sizeof(QJsonPrivate::Value))) + return; if (!a->length) a->tableOffset = sizeof(QJsonPrivate::Array); @@ -492,7 +493,8 @@ void QJsonArray::replace(int i, const QJsonValue &value) bool compressed; int valueSize = QJsonPrivate::Value::requiredStorage(val, &compressed); - detach(valueSize); + if (!detach2(valueSize)) + return; if (!a->length) a->tableOffset = sizeof(QJsonPrivate::Array); @@ -1122,22 +1124,39 @@ bool QJsonArray::operator!=(const QJsonArray &other) const \internal */ void QJsonArray::detach(uint reserve) +{ + Q_UNUSED(reserve) + Q_ASSERT(!reserve); + detach2(0); +} + +/*! + \internal + */ +bool QJsonArray::detach2(uint reserve) { if (!d) { + if (reserve >= QJsonPrivate::Value::MaxSize) { + qWarning("QJson: Document too large to store in data structure"); + return false; + } d = new QJsonPrivate::Data(reserve, QJsonValue::Array); a = static_cast(d->header->root()); d->ref.ref(); - return; + return true; } if (reserve == 0 && d->ref.load() == 1) - return; + return true; QJsonPrivate::Data *x = d->clone(a, reserve); + if (!x) + return false; x->ref.ref(); if (!d->ref.deref()) delete d; d = x; a = static_cast(d->header->root()); + return true; } /*! @@ -1148,7 +1167,7 @@ void QJsonArray::compact() if (!d || !d->compactionCounter) return; - detach(); + detach2(); d->compact(); a = static_cast(d->header->root()); } diff --git a/src/corelib/json/qjsonarray.h b/src/corelib/json/qjsonarray.h index 611e1f4193..0f86cfc988 100644 --- a/src/corelib/json/qjsonarray.h +++ b/src/corelib/json/qjsonarray.h @@ -185,10 +185,10 @@ public: friend class const_iterator; // stl style - inline iterator begin() { detach(); return iterator(this, 0); } + inline iterator begin() { detach2(); return iterator(this, 0); } inline const_iterator begin() const { return const_iterator(this, 0); } inline const_iterator constBegin() const { return const_iterator(this, 0); } - inline iterator end() { detach(); return iterator(this, size()); } + inline iterator end() { detach2(); return iterator(this, size()); } inline const_iterator end() const { return const_iterator(this, size()); } inline const_iterator constEnd() const { return const_iterator(this, size()); } iterator insert(iterator before, const QJsonValue &value) { insert(before.i, value); return before; } @@ -229,7 +229,9 @@ private: QJsonArray(QJsonPrivate::Data *data, QJsonPrivate::Array *array); void initialize(); void compact(); + // ### Qt 6: remove me and merge with detach2 void detach(uint reserve = 0); + bool detach2(uint reserve = 0); QJsonPrivate::Data *d; QJsonPrivate::Array *a; diff --git a/src/corelib/json/qjsondocument.cpp b/src/corelib/json/qjsondocument.cpp index 3ef006d82d..5f8f807cf0 100644 --- a/src/corelib/json/qjsondocument.cpp +++ b/src/corelib/json/qjsondocument.cpp @@ -482,7 +482,7 @@ void QJsonDocument::setObject(const QJsonObject &object) if (d->compactionCounter) o.compact(); else - o.detach(); + o.detach2(); d = o.d; d->ref.ref(); return; @@ -509,7 +509,7 @@ void QJsonDocument::setArray(const QJsonArray &array) if (d->compactionCounter) a.compact(); else - a.detach(); + a.detach2(); d = a.d; d->ref.ref(); return; diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp index e43d811157..8b45dd196b 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/json/qjsonobject.cpp @@ -389,7 +389,8 @@ QJsonObject::iterator QJsonObject::insert(const QString &key, const QJsonValue & int valueOffset = sizeof(QJsonPrivate::Entry) + QJsonPrivate::qStringSize(key, latinKey); int requiredSize = valueOffset + valueSize; - detach(requiredSize + sizeof(QJsonPrivate::offset)); // offset for the new index entry + if (!detach2(requiredSize + sizeof(QJsonPrivate::offset))) // offset for the new index entry + return iterator(); if (!o->length) o->tableOffset = sizeof(QJsonPrivate::Object); @@ -433,7 +434,7 @@ void QJsonObject::remove(const QString &key) if (!keyExists) return; - detach(); + detach2(); o->removeItems(index, 1); ++d->compactionCounter; if (d->compactionCounter > 32u && d->compactionCounter >= unsigned(o->length) / 2u) @@ -460,7 +461,7 @@ QJsonValue QJsonObject::take(const QString &key) return QJsonValue(QJsonValue::Undefined); QJsonValue v(d, o, o->entryAt(index)->value); - detach(); + detach2(); o->removeItems(index, 1); ++d->compactionCounter; if (d->compactionCounter > 32u && d->compactionCounter >= unsigned(o->length) / 2u) @@ -554,7 +555,7 @@ QJsonObject::iterator QJsonObject::find(const QString &key) int index = o ? o->indexOf(key, &keyExists) : 0; if (!keyExists) return end(); - detach(); + detach2(); return iterator(this, index); } @@ -1060,22 +1061,36 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const \internal */ void QJsonObject::detach(uint reserve) +{ + Q_UNUSED(reserve) + Q_ASSERT(!reserve); + detach2(reserve); +} + +bool QJsonObject::detach2(uint reserve) { if (!d) { + if (reserve >= QJsonPrivate::Value::MaxSize) { + qWarning("QJson: Document too large to store in data structure"); + return false; + } d = new QJsonPrivate::Data(reserve, QJsonValue::Object); o = static_cast(d->header->root()); d->ref.ref(); - return; + return true; } if (reserve == 0 && d->ref.load() == 1) - return; + return true; QJsonPrivate::Data *x = d->clone(o, reserve); + if (!x) + return false; x->ref.ref(); if (!d->ref.deref()) delete d; d = x; o = static_cast(d->header->root()); + return true; } /*! @@ -1086,7 +1101,7 @@ void QJsonObject::compact() if (!d || !d->compactionCounter) return; - detach(); + detach2(); d->compact(); o = static_cast(d->header->root()); } diff --git a/src/corelib/json/qjsonobject.h b/src/corelib/json/qjsonobject.h index 8535da4a6c..6fb82b7165 100644 --- a/src/corelib/json/qjsonobject.h +++ b/src/corelib/json/qjsonobject.h @@ -182,10 +182,10 @@ public: friend class const_iterator; // STL style - inline iterator begin() { detach(); return iterator(this, 0); } + inline iterator begin() { detach2(); return iterator(this, 0); } inline const_iterator begin() const { return const_iterator(this, 0); } inline const_iterator constBegin() const { return const_iterator(this, 0); } - inline iterator end() { detach(); return iterator(this, size()); } + inline iterator end() { detach2(); return iterator(this, size()); } inline const_iterator end() const { return const_iterator(this, size()); } inline const_iterator constEnd() const { return const_iterator(this, size()); } iterator erase(iterator it); @@ -215,7 +215,9 @@ private: QJsonObject(QJsonPrivate::Data *data, QJsonPrivate::Object *object); void initialize(); + // ### Qt 6: remove me and merge with detach2 void detach(uint reserve = 0); + bool detach2(uint reserve = 0); void compact(); QString keyAt(int i) const; -- cgit v1.2.3 From 4889269ff0fb37130b332863e82dd7c19564116c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 18 Mar 2015 08:49:09 +0100 Subject: Fix quadratic behavior when converting from QVariant The old code called insert for each item, leading to constant reallocation of the data structure. Instead rely on the fact that a QVariantMap (as well as the variant list) is sorted, so we can convert to the QJson data structure in one go without lots of reallocations. Task-number: QTBUG-44737 Change-Id: Id2d38d278fb9afa5e062c7353b4d4215bdfb993c Reviewed-by: Thiago Macieira --- src/corelib/json/qjsonarray.cpp | 41 ++++++++++++++++++++++++++++++-- src/corelib/json/qjsonobject.cpp | 51 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 6 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp index e8d54b5b87..dc8851e8e7 100644 --- a/src/corelib/json/qjsonarray.cpp +++ b/src/corelib/json/qjsonarray.cpp @@ -256,8 +256,45 @@ QJsonArray QJsonArray::fromStringList(const QStringList &list) QJsonArray QJsonArray::fromVariantList(const QVariantList &list) { QJsonArray array; - for (QVariantList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) - array.append(QJsonValue::fromVariant(*it)); + if (list.isEmpty()) + return array; + + array.detach2(1024); + + QVector values; + values.resize(list.size()); + QJsonPrivate::Value *valueData = values.data(); + uint currentOffset = sizeof(QJsonPrivate::Base); + + for (int i = 0; i < list.size(); ++i) { + QJsonValue val = QJsonValue::fromVariant(list.at(i)); + + bool latinOrIntValue; + int valueSize = QJsonPrivate::Value::requiredStorage(val, &latinOrIntValue); + + if (!array.detach2(valueSize)) + return QJsonArray(); + + QJsonPrivate::Value *v = valueData + i; + v->type = (val.t == QJsonValue::Undefined ? QJsonValue::Null : val.t); + v->latinOrIntValue = latinOrIntValue; + v->latinKey = false; + v->value = QJsonPrivate::Value::valueToStore(val, currentOffset); + if (valueSize) + QJsonPrivate::Value::copyData(val, (char *)array.a + currentOffset, latinOrIntValue); + + currentOffset += valueSize; + array.a->size = currentOffset; + } + + // write table + array.a->tableOffset = currentOffset; + if (!array.detach2(sizeof(QJsonPrivate::offset)*values.size())) + return QJsonArray(); + memcpy(array.a->table(), values.constData(), values.size()*sizeof(uint)); + array.a->length = values.size(); + array.a->size = currentOffset + sizeof(QJsonPrivate::offset)*values.size(); + return array; } diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp index 8b45dd196b..b83c8dd19a 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/json/qjsonobject.cpp @@ -197,11 +197,54 @@ QJsonObject &QJsonObject::operator =(const QJsonObject &other) */ QJsonObject QJsonObject::fromVariantMap(const QVariantMap &map) { - // ### this is implemented the trivial way, not the most efficient way - QJsonObject object; - for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) - object.insert(it.key(), QJsonValue::fromVariant(it.value())); + if (map.isEmpty()) + return object; + + object.detach2(1024); + + QVector offsets; + QJsonPrivate::offset currentOffset; + currentOffset = sizeof(QJsonPrivate::Base); + + // the map is already sorted, so we can simply append one entry after the other and + // write the offset table at the end + for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) { + QString key = it.key(); + QJsonValue val = QJsonValue::fromVariant(it.value()); + + bool latinOrIntValue; + int valueSize = QJsonPrivate::Value::requiredStorage(val, &latinOrIntValue); + + bool latinKey = QJsonPrivate::useCompressed(key); + int valueOffset = sizeof(QJsonPrivate::Entry) + QJsonPrivate::qStringSize(key, latinKey); + int requiredSize = valueOffset + valueSize; + + if (!object.detach2(requiredSize + sizeof(QJsonPrivate::offset))) // offset for the new index entry + return QJsonObject(); + + QJsonPrivate::Entry *e = reinterpret_cast(reinterpret_cast(object.o) + currentOffset); + e->value.type = val.t; + e->value.latinKey = latinKey; + e->value.latinOrIntValue = latinOrIntValue; + e->value.value = QJsonPrivate::Value::valueToStore(val, (char *)e - (char *)object.o + valueOffset); + QJsonPrivate::copyString((char *)(e + 1), key, latinKey); + if (valueSize) + QJsonPrivate::Value::copyData(val, (char *)e + valueOffset, latinOrIntValue); + + offsets << currentOffset; + currentOffset += requiredSize; + object.o->size = currentOffset; + } + + // write table + object.o->tableOffset = currentOffset; + if (!object.detach2(sizeof(QJsonPrivate::offset)*offsets.size())) + return QJsonObject(); + memcpy(object.o->table(), offsets.constData(), offsets.size()*sizeof(uint)); + object.o->length = offsets.size(); + object.o->size = currentOffset + sizeof(QJsonPrivate::offset)*offsets.size(); + return object; } -- cgit v1.2.3