We have moved to a new Sailfish OS Forum. Please start new discussions there.

Revision history [back]

click to hide/show revision 1
initial version

posted 2015-04-04 01:54:54 +0200

[bug] Some QtQuick Canvas drawing coordinates cause application-wide deadlock

Description of problem:

Some X & Y coordinate combinations cause a deadlock in the QtQuick Canvas element - this apparently also deadlocks the GUI thread, resulting in the whole application irrecoverably freezing. This is usually followed by the "application is not responding dialog".

Version-Release number of selected component (if applicable):

Name: qt5-qtdeclarative-qtquick Version: 5.2.1+git19-1.23.3

How reproducible:

always

Steps to Reproduce:

  1. save the following minimal reproducer to a file:

    import QtQuick 2.0

    Canvas { id : canvas width : 800 height : 600

    onPaint : {
        console.log("PAINT!")
        var ctx = canvas.getContext("2d")
    
        // original X & Y values known to cause the deadlock
        //var destX = -2995504
        //var destY = 10467643
    
        // but these "bigger numbers" don't cause the deadlock
        //var destX =  -3000000000000000
        //var destY =   5000000000000000
    
        var destX =  -30000000
        var destY =   50000000
    
        // line width 7 - 5 triggers the deadlock
        ctx.lineWidth = 7
        ctx.arc(destX, destY, 3, 0, 2.0 * Math.PI)
        ctx.stroke()
    }
    
    onPainted : {
        console.log("PAINTED!")
    }
    Timer {
        interval : 10
        running : true
        repeat : true
        onTriggered : {
            console.log("TIMER TRIGGERED")
            canvas.requestPaint()
        }
    }
    

    }

  2. run the file with qmlscene

Actual results:

The application immediately freezes once launched. Checking the log reveals that the deadlock happened after the onPaint handler fired but before the onPainted handled fired.

Example output:

$ qmlscene canvas_test.qml
[D] QWaylandEglClientBufferIntegration::QWaylandEglClientBufferIntegration:62 - Using Wayland-EGL
[D] onPaint:9 - PAINT!

End of strace output (strace qmlscene canvas_test.qml):

recvmsg(28, {msg_name(0)=NULL, msg_iov(1)=[{"l\2\1\1_\0\0\0C\1\0\0.\0\0\0\6\1s\0\7\0\0\0:1.2296\0"..., 2048}], msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 159
recvmsg(28, 0xbed3cb78, MSG_CMSG_CLOEXEC) = -1 EAGAIN (Resource temporarily unavailable)
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 705681374}) = 0
poll([{fd=4, events=POLLIN}, {fd=28, events=POLLIN}], 2, 0) = 1 ([{fd=4, revents=POLLIN}])
read(4, "\5\0\0\0\0\0\0\0", 16)         = 8
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 31
connect(31, {sa_family=AF_LOCAL, sun_path=@"/tmp/maliit-server/dbus-bgxOt3rfge"}, 37) = 0
fcntl64(31, F_GETFL)                    = 0x2 (flags O_RDWR)
fcntl64(31, F_SETFL, O_RDWR|O_NONBLOCK) = 0
geteuid32()                             = 100000
getsockname(31, {sa_family=AF_LOCAL, NULL}, [2]) = 0
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 711724408}) = 0
poll([{fd=31, events=POLLOUT}], 1, 0)   = 1 ([{fd=31, revents=POLLOUT}])
send(31, "\0", 1, MSG_NOSIGNAL)         = 1
send(31, "AUTH EXTERNAL 313030303030\r\n", 28, MSG_NOSIGNAL) = 28
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 718286288}) = 0
poll([{fd=4, events=POLLIN}, {fd=28, events=POLLIN}, {fd=31, events=POLLIN}], 3, 0) = 2 ([{fd=4, revents=POLLIN}, {fd=31, revents=POLLIN}])
read(4, "\7\0\0\0\0\0\0\0", 16)         = 8
read(31, "OK 9c84e1b6d2d892e2427cba0855141"..., 2048) = 37
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 721826651}) = 0
write(2, "[D] onPaint:9 - PAINT!\n", 23[D] onPaint:9 - PAINT!
) = 23
mmap2(NULL, 1921024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x46300000

Expected results:

Canvas safely handles the slightly bogus coordinates without deadlocking the whole application. The coordinates are far outside of the bounding box and should be ignored anyway. This is what happens on desktop (Qt 5.4 on Fedora 21 64 bit) - Canvas has no issues with the weird coordinates and no deadlock occurs.

Example output: (from desktop)

$ qmlscene canvas_test.qml 
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!

etc.

Additional info:

Note from the minimal reproducer that there seem to be a range of the coordinates that cause the issue - it is not just big numbers causing the deadlock - if the number are too big, the deadlock does not happen. It also seems to depend on line width.

Also even though the coordinates that are causing this deadlock are really rather bogus and not something most applications would want to normally use when drawing on the canvas, this bug is still a serious issue as any miscalculated coordinates that hit the deadlock range will freeze the whole application.

This can easily lead to data loss or worse if a Canvas using OS component would be affected.

[bug] Some QtQuick Canvas drawing coordinates cause application-wide deadlock

Description of problem:

Some X & Y coordinate combinations cause a deadlock in the QtQuick Canvas element - this apparently also deadlocks the GUI thread, resulting in the whole application irrecoverably freezing. This is usually followed by the "application is not responding dialog".

Version-Release number of selected component (if applicable):

Name: qt5-qtdeclarative-qtquick Version: 5.2.1+git19-1.23.3

How reproducible:

always

Steps to Reproduce:

  1. save the following minimal reproducer to a file:

    import QtQuick 2.0

    Canvas { id : canvas width : 800 height : 600

    onPaint : {
        console.log("PAINT!")
        var ctx = canvas.getContext("2d")
    
        // original X & Y values known to cause the deadlock
        //var destX = -2995504
        //var destY = 10467643
    
        // but these "bigger numbers" don't cause the deadlock
        //var destX =  -3000000000000000
        //var destY =   5000000000000000
    
        var destX =  -30000000
        var destY =   50000000
    
        // line width 7 - 5 triggers the deadlock
        ctx.lineWidth = 7
        ctx.arc(destX, destY, 3, 0, 2.0 * Math.PI)
        ctx.stroke()
    }
    
    onPainted : {
        console.log("PAINTED!")
    }
    Timer {
        interval : 10
        running : true
        repeat : true
        onTriggered : {
            console.log("TIMER TRIGGERED")
            canvas.requestPaint()
        }
    }
    

    }

  2. run the file with qmlscene

Actual results:

The application immediately freezes once launched. Checking the log reveals that the deadlock happened after the onPaint handler fired but before the onPainted handled fired.

Example output:

$ qmlscene canvas_test.qml
[D] QWaylandEglClientBufferIntegration::QWaylandEglClientBufferIntegration:62 - Using Wayland-EGL
[D] onPaint:9 - PAINT!

End of strace output (strace qmlscene canvas_test.qml):

recvmsg(28, {msg_name(0)=NULL, msg_iov(1)=[{"l\2\1\1_\0\0\0C\1\0\0.\0\0\0\6\1s\0\7\0\0\0:1.2296\0"..., 2048}], msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 159
recvmsg(28, 0xbed3cb78, MSG_CMSG_CLOEXEC) = -1 EAGAIN (Resource temporarily unavailable)
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 705681374}) = 0
poll([{fd=4, events=POLLIN}, {fd=28, events=POLLIN}], 2, 0) = 1 ([{fd=4, revents=POLLIN}])
read(4, "\5\0\0\0\0\0\0\0", 16)         = 8
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 31
connect(31, {sa_family=AF_LOCAL, sun_path=@"/tmp/maliit-server/dbus-bgxOt3rfge"}, 37) = 0
fcntl64(31, F_GETFL)                    = 0x2 (flags O_RDWR)
fcntl64(31, F_SETFL, O_RDWR|O_NONBLOCK) = 0
geteuid32()                             = 100000
getsockname(31, {sa_family=AF_LOCAL, NULL}, [2]) = 0
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 711724408}) = 0
poll([{fd=31, events=POLLOUT}], 1, 0)   = 1 ([{fd=31, revents=POLLOUT}])
send(31, "\0", 1, MSG_NOSIGNAL)         = 1
send(31, "AUTH EXTERNAL 313030303030\r\n", 28, MSG_NOSIGNAL) = 28
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 718286288}) = 0
poll([{fd=4, events=POLLIN}, {fd=28, events=POLLIN}, {fd=31, events=POLLIN}], 3, 0) = 2 ([{fd=4, revents=POLLIN}, {fd=31, revents=POLLIN}])
read(4, "\7\0\0\0\0\0\0\0", 16)         = 8
read(31, "OK 9c84e1b6d2d892e2427cba0855141"..., 2048) = 37
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 721826651}) = 0
write(2, "[D] onPaint:9 - PAINT!\n", 23[D] onPaint:9 - PAINT!
) = 23
mmap2(NULL, 1921024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x46300000

Expected results:

Canvas safely handles the slightly bogus coordinates without deadlocking the whole application. The coordinates are far outside of the bounding box and should be ignored anyway. This is what happens on desktop (Qt 5.4 on Fedora 21 64 bit) - Canvas has no issues with the weird coordinates and no deadlock occurs.

Example output: (from desktop)

$ qmlscene canvas_test.qml 
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!

etc.

Additional info:

Note from the minimal reproducer that there seem to be a range of the coordinates that cause the issue - it is not just big numbers causing the deadlock - if the number are too big, the deadlock does not happen. It also seems to depend on line width.

Also even though the coordinates that are causing this deadlock are really rather bogus and not something most applications would want to normally use when drawing on the canvas, this bug is still a serious issue as any miscalculated coordinates that hit the deadlock range will freeze the whole application.

This can easily lead to data loss or worse if a Canvas using OS component would be affected.

Update

Filled on the Mer Bugzilla as 881.

[bug] Some QtQuick Canvas drawing coordinates cause application-wide deadlock

Description of problem:

Some X & Y coordinate combinations cause a deadlock in the QtQuick Canvas element - this apparently also deadlocks the GUI thread, resulting in the whole application irrecoverably freezing. This is usually followed by the "application is not responding dialog".

Version-Release number of selected component (if applicable):

Name: qt5-qtdeclarative-qtquick Version: 5.2.1+git19-1.23.3

How reproducible:

always

Steps to Reproduce:

  1. save the following minimal reproducer to a file:

import QtQuick 2.0

2.0 Canvas { id : canvas width : 800 height : 600

600

    onPaint : {
     console.log("PAINT!")
     var ctx = canvas.getContext("2d")

     // original X & Y values known to cause the deadlock
     //var destX = -2995504
     //var destY = 10467643

     // but these "bigger numbers" don't cause the deadlock
     //var destX =  -3000000000000000
     //var destY =   5000000000000000

     var destX =  -30000000
     var destY =   50000000

     // line width 7 - 5 triggers the deadlock
     ctx.lineWidth = 7
     ctx.arc(destX, destY, 3, 0, 2.0 * Math.PI)
     ctx.stroke()
 }

 onPainted : {
     console.log("PAINTED!")
 }
 Timer {
     interval : 10
     running : true
     repeat : true
     onTriggered : {
         console.log("TIMER TRIGGERED")
         canvas.requestPaint()
        }
    }
}

}

  1. run the file with qmlscene

Actual results:

The application immediately freezes once launched. Checking the log reveals that the deadlock happened after the onPaint handler fired but before the onPainted handled fired.

Example output:

$ qmlscene canvas_test.qml
[D] QWaylandEglClientBufferIntegration::QWaylandEglClientBufferIntegration:62 - Using Wayland-EGL
[D] onPaint:9 - PAINT!

End of strace output (strace qmlscene canvas_test.qml):

recvmsg(28, {msg_name(0)=NULL, msg_iov(1)=[{"l\2\1\1_\0\0\0C\1\0\0.\0\0\0\6\1s\0\7\0\0\0:1.2296\0"..., 2048}], msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 159
recvmsg(28, 0xbed3cb78, MSG_CMSG_CLOEXEC) = -1 EAGAIN (Resource temporarily unavailable)
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 705681374}) = 0
poll([{fd=4, events=POLLIN}, {fd=28, events=POLLIN}], 2, 0) = 1 ([{fd=4, revents=POLLIN}])
read(4, "\5\0\0\0\0\0\0\0", 16)         = 8
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 31
connect(31, {sa_family=AF_LOCAL, sun_path=@"/tmp/maliit-server/dbus-bgxOt3rfge"}, 37) = 0
fcntl64(31, F_GETFL)                    = 0x2 (flags O_RDWR)
fcntl64(31, F_SETFL, O_RDWR|O_NONBLOCK) = 0
geteuid32()                             = 100000
getsockname(31, {sa_family=AF_LOCAL, NULL}, [2]) = 0
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 711724408}) = 0
poll([{fd=31, events=POLLOUT}], 1, 0)   = 1 ([{fd=31, revents=POLLOUT}])
send(31, "\0", 1, MSG_NOSIGNAL)         = 1
send(31, "AUTH EXTERNAL 313030303030\r\n", 28, MSG_NOSIGNAL) = 28
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 718286288}) = 0
poll([{fd=4, events=POLLIN}, {fd=28, events=POLLIN}, {fd=31, events=POLLIN}], 3, 0) = 2 ([{fd=4, revents=POLLIN}, {fd=31, revents=POLLIN}])
read(4, "\7\0\0\0\0\0\0\0", 16)         = 8
read(31, "OK 9c84e1b6d2d892e2427cba0855141"..., 2048) = 37
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
clock_gettime(CLOCK_MONOTONIC, {350351, 721826651}) = 0
write(2, "[D] onPaint:9 - PAINT!\n", 23[D] onPaint:9 - PAINT!
) = 23
mmap2(NULL, 1921024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x46300000

Expected results:

Canvas safely handles the slightly bogus coordinates without deadlocking the whole application. The coordinates are far outside of the bounding box and should be ignored anyway. This is what happens on desktop (Qt 5.4 on Fedora 21 64 bit) - Canvas has no issues with the weird coordinates and no deadlock occurs.

Example output: (from desktop)

$ qmlscene canvas_test.qml 
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!
qml: TIMER TRIGGERED
qml: TIMER TRIGGERED
qml: PAINT!
qml: PAINTED!

etc.

Additional info:

Note from the minimal reproducer that there seem to be a range of the coordinates that cause the issue - it is not just big numbers causing the deadlock - if the number are too big, the deadlock does not happen. It also seems to depend on line width.

Also even though the coordinates that are causing this deadlock are really rather bogus and not something most applications would want to normally use when drawing on the canvas, this bug is still a serious issue as any miscalculated coordinates that hit the deadlock range will freeze the whole application.

This can easily lead to data loss or worse if a Canvas using OS component would be affected.

Update

Filled on the Mer Bugzilla as 881.