Merge "Merge remote-tracking branch 'origin/5.12.8' into 5.12"

This commit is contained in:
Qt Forward Merge Bot 2020-04-14 12:27:02 +02:00
commit 7d7afe1d2b
10 changed files with 269 additions and 91 deletions

5
configure vendored
View File

@ -271,12 +271,9 @@ macSDKify()
val=$(echo $sdk_val $(echo $val | cut -s -d ' ' -f 2-))
echo "$var=$val"
;;
QMAKE_CFLAGS=*|QMAKE_CXXFLAGS=*)
QMAKE_CFLAGS=*|QMAKE_CXXFLAGS=*|QMAKE_LFLAGS=*)
echo "$line -isysroot $sysroot $version_min_flag"
;;
QMAKE_LFLAGS=*)
echo "$line -Wl,-syslibroot,$sysroot $version_min_flag"
;;
*)
echo "$line"
;;

70
dist/changes-5.12.8 vendored Normal file
View File

@ -0,0 +1,70 @@
Qt 5.12.8 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.12.0 through 5.12.7.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
https://doc.qt.io/qt-5/index.html
The Qt version 5.12 series is binary compatible with the 5.11.x series.
Applications compiled for 5.11 will continue to run with 5.12.
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.
****************************************************************************
* QtCore *
****************************************************************************
- QLockFile:
* Suppressed the warning on QNX that said 'setNativeLocks failed:
"Function not implemented"'. There is no difference in behavior: Qt
will continue not to be able to apply an OS- level file lock, which
means the lock could be accidentally stolen by buggy software. Correct
software using QLockFile should not be affected.
- QXmlStream:
* QTBUG-47417: QXmlStreamReader does now limit the expansion of
entities to 4096 characters. Documents where a single entity
expands to more characters than the limit are not considered well
formed. The limit is there to avoid DoS attacks through
recursively expanding entities when loading untrusted content. Qt
5.15 will add methods that allow changing that limit.
****************************************************************************
* QtSQL *
****************************************************************************
- sqlite:
* Updated to v3.31.1
* [QTBUG-82533] Fixed CVE-2020-9327
****************************************************************************
* QtNetwork *
****************************************************************************
- QSslCertificate:
* Fix a potential heap buffer overflow when parsing certificates
- QTBUG-81762: Fix SSL symbol resolving for OPENSSL_NO_NEXPROTONEG
****************************************************************************
* Platform specific changes *
****************************************************************************
- macOS:
* QTBUG-82986: Improve performance when flushing sublayers
* QTBUG-79139: Avoid repainting OpenGL layers when resizing the window
- xcb/X11:
* QTBUG-76147, QTBUG-76354, QTBUG-68864: Fix handling of minimized state
- QNX:
* QTBUG-81701: QLockFile: Disable flock() on QNX

View File

@ -197,7 +197,7 @@ macx-xcode {
-isysroot$$xcodeSDKInfo(Path, $$sdk)
QMAKE_XARCH_LFLAGS_$${arch} = $$version_min_flags \
-Xarch_$${arch} \
-Wl,-syslibroot,$$xcodeSDKInfo(Path, $$sdk)
-isysroot$$xcodeSDKInfo(Path, $$sdk)
QMAKE_XARCH_CFLAGS += $(EXPORT_QMAKE_XARCH_CFLAGS_$${arch})
QMAKE_XARCH_LFLAGS += $(EXPORT_QMAKE_XARCH_LFLAGS_$${arch})
@ -218,7 +218,7 @@ macx-xcode {
version_min_flag = -m$${version_identifier}-version-min=$$deployment_target
QMAKE_CFLAGS += -isysroot $$QMAKE_MAC_SDK_PATH $$version_min_flag
QMAKE_CXXFLAGS += -isysroot $$QMAKE_MAC_SDK_PATH $$version_min_flag
QMAKE_LFLAGS += -Wl,-syslibroot,$$QMAKE_MAC_SDK_PATH $$version_min_flag
QMAKE_LFLAGS += -isysroot $$QMAKE_MAC_SDK_PATH $$version_min_flag
}
# Enable precompiled headers for multiple architectures

View File

@ -724,54 +724,66 @@ public class QtNative
public static boolean hasClipboardText()
{
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getText() != null)
return true;
try {
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getText() != null)
return true;
}
} catch (Exception e) {
Log.e(QtTAG, "Failed to get clipboard data", e);
}
return false;
}
private static String getClipboardText()
{
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getText() != null)
return primaryClip.getItemAt(i).getText().toString();
try {
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getText() != null)
return primaryClip.getItemAt(i).getText().toString();
}
} catch (Exception e) {
Log.e(QtTAG, "Failed to get clipboard data", e);
}
return "";
}
private static void updatePrimaryClip(ClipData clipData)
{
if (m_usePrimaryClip) {
ClipData clip = m_clipboardManager.getPrimaryClip();
if (Build.VERSION.SDK_INT >= 26) {
if (m_addItemMethod == null) {
Class[] cArg = new Class[2];
cArg[0] = ContentResolver.class;
cArg[1] = ClipData.Item.class;
try {
m_addItemMethod = m_clipboardManager.getClass().getMethod("addItem", cArg);
} catch (Exception e) {
try {
if (m_usePrimaryClip) {
ClipData clip = m_clipboardManager.getPrimaryClip();
if (Build.VERSION.SDK_INT >= 26) {
if (m_addItemMethod == null) {
Class[] cArg = new Class[2];
cArg[0] = ContentResolver.class;
cArg[1] = ClipData.Item.class;
try {
m_addItemMethod = m_clipboardManager.getClass().getMethod("addItem", cArg);
} catch (Exception e) {
}
}
}
}
if (m_addItemMethod != null) {
try {
m_addItemMethod.invoke(m_activity.getContentResolver(), clipData.getItemAt(0));
} catch (Exception e) {
e.printStackTrace();
if (m_addItemMethod != null) {
try {
m_addItemMethod.invoke(m_activity.getContentResolver(), clipData.getItemAt(0));
} catch (Exception e) {
e.printStackTrace();
}
} else {
clip.addItem(clipData.getItemAt(0));
}
m_clipboardManager.setPrimaryClip(clip);
} else {
clip.addItem(clipData.getItemAt(0));
m_clipboardManager.setPrimaryClip(clipData);
m_usePrimaryClip = true;
}
m_clipboardManager.setPrimaryClip(clip);
} else {
m_clipboardManager.setPrimaryClip(clipData);
m_usePrimaryClip = true;
} catch (Exception e) {
Log.e(QtTAG, "Failed to set clipboard data", e);
}
}
@ -785,22 +797,30 @@ public class QtNative
public static boolean hasClipboardHtml()
{
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getHtmlText() != null)
return true;
try {
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getHtmlText() != null)
return true;
}
} catch (Exception e) {
Log.e(QtTAG, "Failed to get clipboard data", e);
}
return false;
}
private static String getClipboardHtml()
{
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getHtmlText() != null)
return primaryClip.getItemAt(i).getHtmlText().toString();
try {
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getHtmlText() != null)
return primaryClip.getItemAt(i).getHtmlText().toString();
}
} catch (Exception e) {
Log.e(QtTAG, "Failed to get clipboard data", e);
}
return "";
}
@ -816,11 +836,15 @@ public class QtNative
public static boolean hasClipboardUri()
{
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getUri() != null)
return true;
try {
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getUri() != null)
return true;
}
} catch (Exception e) {
Log.e(QtTAG, "Failed to get clipboard data", e);
}
return false;
}
@ -828,11 +852,15 @@ public class QtNative
private static String[] getClipboardUris()
{
ArrayList<String> uris = new ArrayList<String>();
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getUri() != null)
uris.add(primaryClip.getItemAt(i).getUri().toString());
try {
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
for (int i = 0; i < primaryClip.getItemCount(); ++i)
if (primaryClip.getItemAt(i).getUri() != null)
uris.add(primaryClip.getItemAt(i).getUri().toString());
}
} catch (Exception e) {
Log.e(QtTAG, "Failed to get clipboard data", e);
}
String[] strings = new String[uris.size()];
strings = uris.toArray(strings);

View File

@ -277,9 +277,19 @@ public:
QHash<QStringView, Entity> entityHash;
QHash<QStringView, Entity> parameterEntityHash;
QXmlStreamSimpleStack<Entity *>entityReferenceStack;
int entityExpansionLimit = 4096;
int entityLength = 0;
inline bool referenceEntity(Entity &entity) {
if (entity.isCurrentlyReferenced) {
raiseWellFormedError(QXmlStream::tr("Recursive entity detected."));
raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected."));
return false;
}
// entityLength represents the amount of additional characters the
// entity expands into (can be negative for e.g. &amp;). It's used to
// avoid DoS attacks through recursive entity expansions
entityLength += entity.value.size() - entity.name.size() - 2;
if (entityLength > entityExpansionLimit) {
raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit."));
return false;
}
entity.isCurrentlyReferenced = true;
@ -830,6 +840,8 @@ entity_done ::= ENTITY_DONE;
/.
case $rule_number:
entityReferenceStack.pop()->isCurrentlyReferenced = false;
if (entityReferenceStack.isEmpty())
entityLength = 0;
clearSym();
break;
./

View File

@ -774,9 +774,19 @@ public:
QHash<QStringView, Entity> entityHash;
QHash<QStringView, Entity> parameterEntityHash;
QXmlStreamSimpleStack<Entity *>entityReferenceStack;
int entityExpansionLimit = 4096;
int entityLength = 0;
inline bool referenceEntity(Entity &entity) {
if (entity.isCurrentlyReferenced) {
raiseWellFormedError(QXmlStream::tr("Recursive entity detected."));
raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected."));
return false;
}
// entityLength represents the amount of additional characters the
// entity expands into (can be negative for e.g. &amp;). It's used to
// avoid DoS attacks through recursive entity expansions
entityLength += entity.value.size() - entity.name.size() - 2;
if (entityLength > entityExpansionLimit) {
raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit."));
return false;
}
entity.isCurrentlyReferenced = true;
@ -1308,6 +1318,8 @@ bool QXmlStreamReaderPrivate::parse()
case 10:
entityReferenceStack.pop()->isCurrentlyReferenced = false;
if (entityReferenceStack.isEmpty())
entityLength = 0;
clearSym();
break;

View File

@ -47,6 +47,8 @@
#include <QScopedPointer>
#include "qiosurfacegraphicsbuffer.h"
#include <unordered_map>
QT_BEGIN_NAMESPACE
class QCocoaBackingStore : public QRasterBackingStore
@ -71,8 +73,9 @@ private:
void redrawRoundedBottomCorners(CGRect) const;
};
class QCALayerBackingStore : public QCocoaBackingStore
class QCALayerBackingStore : public QObject, public QCocoaBackingStore
{
Q_OBJECT
public:
QCALayerBackingStore(QWindow *window);
~QCALayerBackingStore();
@ -119,6 +122,11 @@ private:
QMacNotificationObserver m_backingPropertiesObserver;
std::list<std::unique_ptr<GraphicsBuffer>> m_buffers;
void flushSubWindow(QWindow *window);
std::unordered_map<QWindow*, std::unique_ptr<QCALayerBackingStore>> m_subWindowBackingstores;
void windowDestroyed(QObject *object);
bool m_clearSurfaceOnPaint = true;
};
QT_END_NAMESPACE

View File

@ -394,7 +394,7 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
// Although undocumented, QBackingStore::beginPaint expects the painted region
// to be cleared before use if the window has a surface format with an alpha.
// Fresh IOSurfaces are already cleared, so we don't need to clear those.
if (!bufferWasRecreated && window()->format().hasAlpha()) {
if (m_clearSurfaceOnPaint && !bufferWasRecreated && window()->format().hasAlpha()) {
qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use";
QPainter painter(m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
@ -523,9 +523,13 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
if (!prepareForFlush())
return;
if (flushedWindow != window()) {
flushSubWindow(flushedWindow);
return;
}
QMacAutoReleasePool pool;
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
// If the backingstore is just flushed, without being painted to first, then we may
@ -560,7 +564,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// are committed as part of a display-cycle instead of on the next runloop pass. This
// means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush
// with other pending view and layer updates.
backingStoreView.window.viewsNeedDisplay = YES;
flushedView.window.viewsNeedDisplay = YES;
if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) {
// The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable,
@ -568,28 +572,10 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
flushedView.layer.contents = nil;
}
if (flushedView == backingStoreView) {
qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
<< "to" << flushedView.layer << "of" << flushedView;
flushedView.layer.contents = backBufferSurface;
} else {
auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
auto scale = flushedView.layer.contentsScale;
subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
<< "to" << flushedView.layer << "of" << flushedView;
// We make a copy of the image data up front, which means we don't
// need to mark the IOSurface as being in use. FIXME: Investigate
// if there's a cheaper way to get sub-image data to a layer.
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
QImage subImage = m_buffers.back()->asImage()->copy(QRectF::fromCGRect(subviewRect).toRect());
m_buffers.back()->unlock();
qCInfo(lcQpaBackingStore) << "Flushing" << subImage
<< "to" << flushedView.layer << "of subview" << flushedView;
QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
QCFType<CGImageRef>(subImage.toCGImage()), colorSpace());
flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
}
flushedView.layer.contents = backBufferSurface;
// Since we may receive multiple flushes before a new frame is started, we do not
// swap any buffers just yet. Instead we check in the next beginPaint if the layer's
@ -601,6 +587,53 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// the window server.
}
void QCALayerBackingStore::flushSubWindow(QWindow *subWindow)
{
qCInfo(lcQpaBackingStore) << "Flushing sub-window" << subWindow
<< "via its own backingstore";
auto &subWindowBackingStore = m_subWindowBackingstores[subWindow];
if (!subWindowBackingStore) {
subWindowBackingStore.reset(new QCALayerBackingStore(subWindow));
QObject::connect(subWindow, &QObject::destroyed, this, &QCALayerBackingStore::windowDestroyed);
subWindowBackingStore->m_clearSurfaceOnPaint = false;
}
auto subWindowSize = subWindow->size();
static const auto kNoStaticContents = QRegion();
subWindowBackingStore->resize(subWindowSize, kNoStaticContents);
auto subWindowLocalRect = QRect(QPoint(), subWindowSize);
subWindowBackingStore->beginPaint(subWindowLocalRect);
QPainter painter(subWindowBackingStore->m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(subWindow->handle())->view();
auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
auto scale = flushedView.layer.contentsScale;
subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
const QImage *backingStoreImage = m_buffers.back()->asImage();
painter.drawImage(subWindowLocalRect, *backingStoreImage, QRectF::fromCGRect(subviewRect));
m_buffers.back()->unlock();
painter.end();
subWindowBackingStore->endPaint();
subWindowBackingStore->flush(subWindow, subWindowLocalRect, QPoint());
qCInfo(lcQpaBackingStore) << "Done flushing sub-window" << subWindow;
}
void QCALayerBackingStore::windowDestroyed(QObject *object)
{
auto *window = static_cast<QWindow*>(object);
qCInfo(lcQpaBackingStore) << "Removing backingstore for sub-window" << window;
m_subWindowBackingstores.erase(window);
}
#ifndef QT_NO_OPENGL
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, bool translucentBackground)
@ -734,4 +767,6 @@ QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
return &m_image;
}
#include "moc_qcocoabackingstore.cpp"
QT_END_NAMESPACE

View File

@ -332,11 +332,8 @@ bool QIOSContext::verifyGraphicsHardwareAvailability()
);
});
if (applicationBackgrounded) {
static const char warning[] = "OpenGL ES calls are not allowed while an application is backgrounded";
Q_ASSERT_X(!applicationBackgrounded, "QIOSContext", warning);
qCWarning(lcQpaGLContext, warning);
}
if (applicationBackgrounded)
qCWarning(lcQpaGLContext, "OpenGL ES calls are not allowed while an application is backgrounded");
return !applicationBackgrounded;
}

View File

@ -393,8 +393,6 @@ public:
return true;
}
QXmlStreamReader reader(&inputFile);
/* See testcases.dtd which reads: 'Nonvalidating parsers
* must also accept "invalid" testcases, but validating ones must reject them.' */
if(type == QLatin1String("invalid") || type == QLatin1String("valid"))
@ -580,6 +578,8 @@ private slots:
void roundTrip() const;
void roundTrip_data() const;
void entityExpansionLimit() const;
private:
static QByteArray readFile(const QString &filename);
@ -1756,6 +1756,25 @@ void tst_QXmlStream::roundTrip_data() const
"</root>\n";
}
void tst_QXmlStream::entityExpansionLimit() const
{
QString xml = QStringLiteral("<?xml version=\"1.0\"?>"
"<!DOCTYPE foo ["
"<!ENTITY a \"0123456789\" >"
"<!ENTITY b \"&a;&a;&a;&a;&a;&a;&a;&a;&a;&a;\" >"
"<!ENTITY c \"&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;\" >"
"<!ENTITY d \"&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;\" >"
"]>"
"<foo>&d;&d;&d;</foo>");
{
QXmlStreamReader reader(xml);
do {
reader.readNext();
} while (!reader.atEnd());
QCOMPARE(reader.error(), QXmlStreamReader::NotWellFormedError);
}
}
void tst_QXmlStream::roundTrip() const
{
QFETCH(QString, in);