Bug 390725 - Using setColorSpace on a document in python leads to safe-asserts and memory leaks.
Summary: Using setColorSpace on a document in python leads to safe-asserts and memory ...
Status: RESOLVED FIXED
Alias: None
Product: krita
Classification: Applications
Component: Scripting (show other bugs)
Version: git master (please specify the git hash!)
Platform: Other Linux
: NOR major
Target Milestone: ---
Assignee: Krita Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-02-19 09:52 UTC by wolthera
Modified: 2018-02-21 14:10 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description wolthera 2018-02-19 09:52:47 UTC
Decided to make a seperate bug task for this one.

To Reproduce
------------
1. Download this sample comic project https://share.kde.org/index.php/s/hv1S25gBVq4pTwh, unzip it somewhere.
2. Enable the Comic Project Management Tools under settings->configure Krita->python manager.
3. (Re)start Krita in terminal.
4. Open the comics manager docker
5. "Open Project"->Navigate to the sample comic project folder, and select the comicConfig.json
6. Then, when the comic is loaded, press "export comic"
7. Keep your eyes on the terminal, once the comic is done exporting it should show this for each page in the docker: SAFE ASSERT (krita): "!sanityCheckPointer.isValid()" in file /home/wolthera/krita/src/libs/ui/KisDocument.cpp, line 490

Other
-----

I spent some time with boud trying to figure out what caused this last august, but we couldn't figure out what did.

I suspect it may have something to do with that the documents are never added to the Krita GUI, which is not good because that means headless exporting doesn't work at all.
Comment 1 wolthera 2018-02-19 22:07:39 UTC
Okay, I actually figured out what is causing this. It is specifically caused by Document::setColorSpace().

For some reason, the document is always locked there when getting to the refreshgraph fuction, casuing errors and thus causing safe-asserts.
Comment 2 wolthera 2018-02-19 23:31:47 UTC
Actually, disabling the use of setColorSpace doesn't solve the safeAssert, it just solves the refresh warning.

The safe assert is caused by the following:

1. Open a document in python
2. get the rootNode of the object.
3. Write a function to itterate over the child nodes, setting their labels or whatever, and if a child node has children, apply the function on those. Put the root node in this.
4. close the document.

3 in particular seems to cause the document not to close, with a simple script like this:
-------------------------------------------------
def removeLayers(self, labels, node):
        if node.colorLabel() in labels:
            node.remove()
        else:
            if node.childNodes():
                for child in node.childNodes():
                    self.removeLayers(labels, node=child)
Comment 3 Halla Rempt 2018-02-21 11:37:37 UTC
I don't get a safe assert, but if I run this script, I get a crash on closing Krita:

from krita import *

def removeLayers(node):
    if node.childNodes():
        for child in node.childNodes():
            removeLayers(child)
    node.remove()
            

d = Application.createDocument(100, 100, "Test", "RGBA", "U8", "", 120.0)

root = d.rootNode();
print(root.childNodes())

l2 = d.createNode("layer2", "paintLayer")
print(l2)

root.addChildNode(l2, None)
print(root.childNodes())

removeLayers(root)


Thread 1 "krita" received signal SIGSEGV, Segmentation fault.
initFontUnlocked () at kernel/qguiapplication.cpp:238
238                 new QFont(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFont());
(gdb) bt
#0  initFontUnlocked () at kernel/qguiapplication.cpp:238
#1  0x00007fffedb5d1ed in QGuiApplication::font () at kernel/qguiapplication.cpp:3015
#2  0x00007fffedbfc98e in QFont::QFont (this=0x7534b68) at text/qfont.cpp:611
#3  0x00007fffee5372d0 in QWidgetData::QWidgetData (this=0x7534b30) at kernel/qwidget.h:103
#4  QWidgetPrivate::QWidgetPrivate (this=0x7534a00, version=330240) at kernel/qwidget.cpp:296
#5  0x00007fffee722192 in QDialogPrivate::QDialogPrivate (this=0x7534a00)
    at ../../src/widgets/dialogs/qdialog_p.h:86
#6  QProgressDialogPrivate::QProgressDialogPrivate (this=0x7534a00) at dialogs/qprogressdialog.cpp:77
#7  QProgressDialog::QProgressDialog (this=0x62f3cd0, labelText=..., cancelButtonText=..., minimum=0, 
    maximum=0, parent=0x0, f=...) at dialogs/qprogressdialog.cpp:324
#8  0x00007ffff7898d0b in KisAsyncActionFeedback::KisAsyncActionFeedback (this=0x7fffffffd480, message=..., 
    parent=0x0) at /home/boud/dev/krita/libs/ui/kis_async_action_feedback.cpp:33
#9  0x00007ffff78795e0 in KisDocument::waitForSavingToComplete (this=this@entry=0x938bb00)
    at /home/boud/dev/krita/libs/ui/KisDocument.cpp:1596
#10 0x00007ffff787cff8 in KisDocument::~KisDocument (this=0x938bb00, __in_chrg=<optimized out>)
    at /home/boud/dev/krita/libs/ui/KisDocument.cpp:444
#11 0x00007ffff787d429 in KisDocument::~KisDocument (this=0x938bb00, __in_chrg=<optimized out>)
    at /home/boud/dev/krita/libs/ui/KisDocument.cpp:495
#12 0x00007ffff78b7921 in KisPart::~KisPart (
    this=0x7ffff7dda550 <_ZZN12_GLOBAL__N_116Q_QGS_s_instance13innerFunctionEvE6holder>, 
    __in_chrg=<optimized out>) at /home/boud/dev/krita/libs/ui/KisPart.cpp:144
#13 0x00007ffff78b7c49 in (anonymous namespace)::Q_QGS_s_instance::Holder::~Holder (this=<optimized out>, 
    __in_chrg=<optimized out>) at /home/boud/dev/krita/libs/ui/KisPart.cpp:82
#14 0x00007fffec76f129 in __run_exit_handlers () from /lib64/libc.so.6
#15 0x00007fffec76f175 in exit () from /lib64/libc.so.6
#16 0x00007fffec7586dc in __libc_start_main () from /lib64/libc.so.6
#17 0x00000000004063a9 in _start () at ../sysdeps/x86_64/start.S:118
Comment 4 Halla Rempt 2018-02-21 12:11:10 UTC
Okay, it turns out that if one uses createDocument, then one needs to explicitly close the document in the same script, otherwise it'll be kept alive by Krita:

d.close()
Comment 5 Halla Rempt 2018-02-21 14:10:09 UTC
Once d.close() is called, no errors happen (at least not anymore after today's commits). However, there's still a gotcha when running stuff from scripter. Everything that's run in scripter's top-level context will not be deleted when the script is done.


from krita import *
d = Application.createDocument()
root = d.rootNode()
d.close()

This will close and delete the document created; it will not delete the "root" object, because the "root" object is in the global Python context and will only be removed when Krita exits. It will also keep a strong reference to the document's image's root KisNode, which means that that won't be deleted either until the Python plugin is unloaded.

The solution for now is to run code in another context, for instance:

from krita import *

def test():
    d = Application.createDocument()
    root = d.rootNode()
    d.close()

test()