Merge remote-tracking branch 'origin/5.9.3' into 5.9

Change-Id: I9add7e07ff1b6a1cf52f59dbb8319f30e114e5fc
This commit is contained in:
Liang Qi 2017-11-23 09:47:49 +01:00
commit 19378fa008
4 changed files with 367 additions and 153 deletions

144
dist/changes-5.9.3 vendored Normal file
View File

@ -0,0 +1,144 @@
Qt 5.9.3 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.9.0 through 5.9.2.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
http://doc.qt.io/qt-5/index.html
The Qt version 5.9 series is binary compatible with the 5.8.x series.
Applications compiled for 5.8 will continue to run with 5.9.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
https://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* Qt 5.9.3 Changes *
****************************************************************************
QtCore
------
- QFileSystemWatcher:
* [QTBUG-64171] Fixed a bug that would cause the application to crash if
QFileSystemWatcher was created in an auxiliary thread on Windows.
- QStorageInfo:
* [QTBUG-61420] Fixed decoding of volume labels containing certain
uncommon characters on Linux.
- QThreadPool:
* Improved performance with large amount of QRunnable items.
QtGui
------
- [QTBUG-64239] Fixed memory corruption on scaled emojis.
- [QTBUG-63846] Fixed dragging inside a modal window when a
QShapedPixmapWindow is used.
- [QTBUG-61777] Fixed painting of zero-length lines with scaling.
- [QTBUG-61244] Fixed centering of some items in layouts.
- [QTBUG-63168] Fixed a crash when reparenting QWindowContainer.
QtNetwork
---------
- QHostAddress:
* [QTBUG-63764] Fixed a problem in QHostAddress not detaching in its
setters and thus spoiling shared data.
- QNetworkAccessManager:
* [QTBUG-63075] Added support for HTTP status 308.
* [QTBUG-61300] Fixed a problem with mixing headers from different
responses.
* [QTBUG-63471] Fixed redirects support in HTTP/2 protocol handler.
* [QTBUG-63313] Fixed cookies received during a redirect not being
applied in the redirect.
* [QTBUG-63142] Fixed HTTP method always being changed to GET when
redirected with 307 and 308.
- QNetworkCookieJar:
* Fixed cookies with a root path ("/") not matching an empty path ("").
QtSql
------
- PostgreSQL:
* Fixed handling of binary data for PostgreSQL 9.x and later
* Fixed detection of PostgreSQL 9.x and later
- OCI:
* [QTBUG-57765] Fixed a bug that would see some cached results returned
when issuing a forward only query
QtWidgets
---------
- QAction:
* [QTBUG-62006] Ensured setData() does not emit changed() if no change
happened.
- QDockWidget:
* [QTBUG-63526] Fixed an issue in QDockWidgets where the widget would
not resize despite showing a resize cursor.
- QHeaderView:
* [QTBUG-54601] Fixed resizing when hidden sections were involved.
* [QTBUG-64036] Ensured maximumSectionSize property is honored during
resizeSections().
- QListView:
* [QTBUG-45427] Fixed the laying out of a QListView in a grid layout
after the dataChanged() signal is emitted.
- QMenuBar
* [QTBUG-34160] Fixed a problem with adding the same QAction to more than
one menu.
- QWidget
* [QTBUG-56860] Fixed widget losing focus after showing menu second time.
- QWizard:
* [QTBUG-46894] Fixed the shortcut for the Next button on Windows.
Platform-specific changes
-------------------------
- Cocoa:
* optimize backingstore flush on 10-bit displays
* [QTBUG-57076] [QTBUG-63712] Attach menu items when updating the menubar
* [QTBUG-63444] Toggle titlebar transparency to support unified toolbar
- iOS:
* [QTBUG-57428][QTBUG-63660] add support for adding mimetypes other than text
on the clipboard
- Windows:
* [QTBUG-63654] Windows font database: Remove clamping of default font size
- X11:
* [QTBUG-48034] Don't misdetect certain trackballs as tablets
* [QTBUG-62840] Fix crash on X servers with BGR888 display
Third-Party Code
----------------
- Improved documentation about Freetype 2 licenses.
- Updated Sqlite to fix CVE-2017-10989.
- Updated bundled libpng to version 1.6.34.
Tools
-----
* qmake:
- [QTBUG-63409] Fixed a build error with MSVC when concrt.h was included
while exceptions are disabled.
- [QTBUG-62985] Fixed a bug that caused the accidental creation of files
called "NUL" when using MinGW.

View File

@ -720,184 +720,189 @@ public class QtActivityDelegate
Bundle extras = m_activity.getIntent().getExtras();
if (extras != null) {
if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
&&*/ extras.containsKey("debug_ping")
&& extras.getString("debug_ping").equals("true")) {
try {
final String dc = "--Added-by-androiddeployqt--/debugger.command";
String debuggerCommand =
new BufferedReader(new InputStreamReader(m_activity.getAssets().open(dc))).readLine();
String packagePath =
m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(),
PackageManager.GET_CONFIGURATIONS).dataDir + "/";
try {
final String dc = "--Added-by-androiddeployqt--/debugger.command";
String debuggerCommand =
new BufferedReader(new InputStreamReader(m_activity.getAssets().open(dc))).readLine();
if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
&&*/ extras.containsKey("debug_ping")
&& extras.getString("debug_ping").equals("true")) {
try {
String packagePath =
m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(),
PackageManager.GET_CONFIGURATIONS).dataDir + "/";
debugLog("extra parameters: " + extras);
String packageName = m_activity.getPackageName();
String pingFile = extras.getString("ping_file");
String pongFile = extras.getString("pong_file");
String gdbserverSocket = extras.getString("gdbserver_socket");
String gdbserverCommand = packagePath + debuggerCommand + gdbserverSocket;
String pingSocket = extras.getString("ping_socket");
boolean usePing = pingFile != null;
boolean usePong = pongFile != null;
boolean useSocket = gdbserverSocket != null;
boolean usePingSocket = pingSocket != null;
int napTime = 200; // milliseconds between file accesses
int timeOut = 30000; // ms until we give up on ping and pong
int maxAttempts = timeOut / napTime;
debugLog("extra parameters: " + extras);
String packageName = m_activity.getPackageName();
String pingFile = extras.getString("ping_file");
String pongFile = extras.getString("pong_file");
String gdbserverSocket = extras.getString("gdbserver_socket");
String gdbserverCommand = packagePath + debuggerCommand + gdbserverSocket;
String pingSocket = extras.getString("ping_socket");
boolean usePing = pingFile != null;
boolean usePong = pongFile != null;
boolean useSocket = gdbserverSocket != null;
boolean usePingSocket = pingSocket != null;
int napTime = 200; // milliseconds between file accesses
int timeOut = 30000; // ms until we give up on ping and pong
int maxAttempts = timeOut / napTime;
if (gdbserverSocket != null) {
debugLog("removing gdb socket " + gdbserverSocket);
new File(gdbserverSocket).delete();
}
if (usePing) {
debugLog("removing ping file " + pingFile);
File ping = new File(pingFile);
if (ping.exists()) {
if (!ping.delete())
debugLog("ping file cannot be deleted");
if (gdbserverSocket != null) {
debugLog("removing gdb socket " + gdbserverSocket);
new File(gdbserverSocket).delete();
}
}
if (usePong) {
debugLog("removing pong file " + pongFile);
File pong = new File(pongFile);
if (pong.exists()) {
if (!pong.delete())
debugLog("pong file cannot be deleted");
}
}
debugLog("starting " + gdbserverCommand);
m_debuggerProcess = Runtime.getRuntime().exec(gdbserverCommand);
debugLog("gdbserver started");
if (useSocket) {
int i;
for (i = 0; i < maxAttempts; ++i) {
debugLog("waiting for socket at " + gdbserverSocket + ", attempt " + i);
File file = new File(gdbserverSocket);
if (file.exists()) {
file.setReadable(true, false);
file.setWritable(true, false);
file.setExecutable(true, false);
break;
if (usePing) {
debugLog("removing ping file " + pingFile);
File ping = new File(pingFile);
if (ping.exists()) {
if (!ping.delete())
debugLog("ping file cannot be deleted");
}
Thread.sleep(napTime);
}
if (i == maxAttempts) {
debugLog("time out when waiting for debug socket");
return false;
if (usePong) {
debugLog("removing pong file " + pongFile);
File pong = new File(pongFile);
if (pong.exists()) {
if (!pong.delete())
debugLog("pong file cannot be deleted");
}
}
debugLog("socket ok");
} else {
debugLog("socket not used");
}
debugLog("starting " + gdbserverCommand);
m_debuggerProcess = Runtime.getRuntime().exec(gdbserverCommand);
debugLog("gdbserver started");
if (usePingSocket) {
DebugWaitRunnable runnable = new DebugWaitRunnable(pingSocket);
Thread waitThread = new Thread(runnable);
waitThread.start();
if (useSocket) {
int i;
for (i = 0; i < maxAttempts; ++i) {
debugLog("waiting for socket at " + gdbserverSocket + ", attempt " + i);
File file = new File(gdbserverSocket);
if (file.exists()) {
file.setReadable(true, false);
file.setWritable(true, false);
file.setExecutable(true, false);
break;
}
Thread.sleep(napTime);
}
int i;
for (i = 0; i < maxAttempts && waitThread.isAlive(); ++i) {
debugLog("Waiting for debug socket connect");
debugLog("go to sleep");
Thread.sleep(napTime);
}
if (i == maxAttempts) {
debugLog("time out when waiting for debug socket");
return false;
}
if (i == maxAttempts) {
debugLog("time out when waiting for ping socket");
runnable.shutdown();
return false;
}
if (runnable.wasFailure) {
debugLog("Could not connect to debug client");
return false;
debugLog("socket ok");
} else {
debugLog("Got pid acknowledgment");
debugLog("socket not used");
}
}
if (usePing) {
// Tell we are ready.
debugLog("writing ping at " + pingFile);
FileWriter writer = new FileWriter(pingFile);
writer.write("" + android.os.Process.myPid());
writer.close();
File file = new File(pingFile);
file.setReadable(true, false);
file.setWritable(true, false);
file.setExecutable(true, false);
debugLog("wrote ping");
} else {
debugLog("ping not requested");
}
if (usePingSocket) {
DebugWaitRunnable runnable = new DebugWaitRunnable(pingSocket);
Thread waitThread = new Thread(runnable);
waitThread.start();
// Wait until other side is ready.
if (usePong) {
int i;
for (i = 0; i < maxAttempts; ++i) {
debugLog("waiting for pong at " + pongFile + ", attempt " + i);
File file = new File(pongFile);
if (file.exists()) {
file.delete();
break;
int i;
for (i = 0; i < maxAttempts && waitThread.isAlive(); ++i) {
debugLog("Waiting for debug socket connect");
debugLog("go to sleep");
Thread.sleep(napTime);
}
debugLog("go to sleep");
Thread.sleep(napTime);
}
debugLog("Removing pingFile " + pingFile);
new File(pingFile).delete();
if (i == maxAttempts) {
debugLog("time out when waiting for pong file");
return false;
if (i == maxAttempts) {
debugLog("time out when waiting for ping socket");
runnable.shutdown();
return false;
}
if (runnable.wasFailure) {
debugLog("Could not connect to debug client");
return false;
} else {
debugLog("Got pid acknowledgment");
}
}
debugLog("got pong " + pongFile);
} else {
debugLog("pong not requested");
if (usePing) {
// Tell we are ready.
debugLog("writing ping at " + pingFile);
FileWriter writer = new FileWriter(pingFile);
writer.write("" + android.os.Process.myPid());
writer.close();
File file = new File(pingFile);
file.setReadable(true, false);
file.setWritable(true, false);
file.setExecutable(true, false);
debugLog("wrote ping");
} else {
debugLog("ping not requested");
}
// Wait until other side is ready.
if (usePong) {
int i;
for (i = 0; i < maxAttempts; ++i) {
debugLog("waiting for pong at " + pongFile + ", attempt " + i);
File file = new File(pongFile);
if (file.exists()) {
file.delete();
break;
}
debugLog("go to sleep");
Thread.sleep(napTime);
}
debugLog("Removing pingFile " + pingFile);
new File(pingFile).delete();
if (i == maxAttempts) {
debugLog("time out when waiting for pong file");
return false;
}
debugLog("got pong " + pongFile);
} else {
debugLog("pong not requested");
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SecurityException se) {
se.printStackTrace();
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SecurityException se) {
se.printStackTrace();
}
}
if (/*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
&&*/ extras.containsKey("qml_debug")
&& extras.getString("qml_debug").equals("true")) {
String qmljsdebugger;
if (extras.containsKey("qmljsdebugger")) {
qmljsdebugger = extras.getString("qmljsdebugger");
qmljsdebugger.replaceAll("\\s", ""); // remove whitespace for security
} else {
qmljsdebugger = "port:3768";
if (/*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
&&*/ extras.containsKey("qml_debug")
&& extras.getString("qml_debug").equals("true")) {
String qmljsdebugger;
if (extras.containsKey("qmljsdebugger")) {
qmljsdebugger = extras.getString("qmljsdebugger");
qmljsdebugger.replaceAll("\\s", ""); // remove whitespace for security
} else {
qmljsdebugger = "port:3768";
}
m_applicationParameters += "\t-qmljsdebugger=" + qmljsdebugger;
}
m_applicationParameters += "\t-qmljsdebugger=" + qmljsdebugger;
}
if (extras.containsKey("extraenvvars")) {
try {
m_environmentVariables += "\t" + new String(Base64.decode(extras.getString("extraenvvars"), Base64.DEFAULT), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
if (extras.containsKey("extraenvvars")) {
try {
m_environmentVariables += "\t" + new String(Base64.decode(extras.getString("extraenvvars"), Base64.DEFAULT), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (extras.containsKey("extraappparams")) {
try {
m_applicationParameters += "\t" + new String(Base64.decode(extras.getString("extraappparams"), Base64.DEFAULT), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
if (extras.containsKey("extraappparams")) {
try {
m_applicationParameters += "\t" + new String(Base64.decode(extras.getString("extraappparams"), Base64.DEFAULT), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
// This is not an error, so keep it silent
// e.printStackTrace();
}
} // extras != null

View File

@ -214,13 +214,15 @@ bool QSemaphore::tryAcquire(int n)
bool QSemaphore::tryAcquire(int n, int timeout)
{
Q_ASSERT_X(n >= 0, "QSemaphore::tryAcquire", "parameter 'n' must be non-negative");
if (timeout < 0)
return tryAcquire(n);
// We're documented to accept any negative value as "forever"
// but QDeadlineTimer only accepts -1.
timeout = qMax(timeout, -1);
QDeadlineTimer timer(timeout);
QMutexLocker locker(&d->mutex);
qint64 remainingTime = timer.remainingTime();
while (n > d->avail && remainingTime > 0) {
while (n > d->avail && remainingTime != 0) {
if (!d->cond.wait(locker.mutex(), remainingTime))
return false;
remainingTime = timer.remainingTime();

View File

@ -41,6 +41,8 @@ private slots:
void tryAcquireWithTimeout_data();
void tryAcquireWithTimeout();
void tryAcquireWithTimeoutStarvation();
void tryAcquireWithTimeoutForever_data();
void tryAcquireWithTimeoutForever();
void producerConsumer();
};
@ -155,21 +157,25 @@ void tst_QSemaphore::tryAcquire()
semaphore.release();
QCOMPARE(semaphore.available(), 1);
QVERIFY(!semaphore.tryAcquire(2));
QVERIFY(!semaphore.tryAcquire(2, 0));
QCOMPARE(semaphore.available(), 1);
semaphore.release();
QCOMPARE(semaphore.available(), 2);
QVERIFY(!semaphore.tryAcquire(3));
QVERIFY(!semaphore.tryAcquire(3, 0));
QCOMPARE(semaphore.available(), 2);
semaphore.release(10);
QCOMPARE(semaphore.available(), 12);
QVERIFY(!semaphore.tryAcquire(100));
QVERIFY(!semaphore.tryAcquire(100, 0));
QCOMPARE(semaphore.available(), 12);
semaphore.release(10);
QCOMPARE(semaphore.available(), 22);
QVERIFY(!semaphore.tryAcquire(100));
QVERIFY(!semaphore.tryAcquire(100, 0));
QCOMPARE(semaphore.available(), 22);
QVERIFY(semaphore.tryAcquire());
@ -178,23 +184,38 @@ void tst_QSemaphore::tryAcquire()
QVERIFY(semaphore.tryAcquire());
QCOMPARE(semaphore.available(), 20);
semaphore.release(2);
QVERIFY(semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 21);
QVERIFY(semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 20);
QVERIFY(semaphore.tryAcquire(10));
QCOMPARE(semaphore.available(), 10);
semaphore.release(10);
QVERIFY(semaphore.tryAcquire(10, 0));
QCOMPARE(semaphore.available(), 10);
QVERIFY(semaphore.tryAcquire(10));
QCOMPARE(semaphore.available(), 0);
// should not be able to acquire more
QVERIFY(!semaphore.tryAcquire());
QVERIFY(!semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 0);
QVERIFY(!semaphore.tryAcquire());
QVERIFY(!semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 0);
QVERIFY(!semaphore.tryAcquire(10));
QVERIFY(!semaphore.tryAcquire(10, 0));
QCOMPARE(semaphore.available(), 0);
QVERIFY(!semaphore.tryAcquire(10));
QVERIFY(!semaphore.tryAcquire(10, 0));
QCOMPARE(semaphore.available(), 0);
}
@ -344,6 +365,48 @@ void tst_QSemaphore::tryAcquireWithTimeoutStarvation()
QVERIFY(consumer.wait());
}
void tst_QSemaphore::tryAcquireWithTimeoutForever_data()
{
QTest::addColumn<int>("timeout");
QTest::newRow("-1") << -1;
// tryAcquire is documented to take any negative value as "forever"
QTest::newRow("INT_MIN") << INT_MIN;
}
void tst_QSemaphore::tryAcquireWithTimeoutForever()
{
enum { WaitTime = 1000 };
struct Thread : public QThread {
QSemaphore sem;
void run() override
{
QTest::qWait(WaitTime);
sem.release(2);
}
};
QFETCH(int, timeout);
Thread t;
// sanity check it works if we can immediately acquire
t.sem.release(11);
QVERIFY(t.sem.tryAcquire(1, timeout));
QVERIFY(t.sem.tryAcquire(10, timeout));
// verify that we do wait for at least WaitTime if we can't acquire immediately
QElapsedTimer timer;
timer.start();
t.start();
QVERIFY(t.sem.tryAcquire(1, timeout));
QVERIFY(timer.elapsed() >= WaitTime);
QVERIFY(t.wait());
QCOMPARE(t.sem.available(), 1);
}
const char alphabet[] = "ACGTH";
const int AlphabetSize = sizeof(alphabet) - 1;