Skip to content

TK State Change Issue Causing Seg Fault #72

Open
@jweezy24

Description

@jweezy24

Hello,

On my Linux machine I kept encountering this error.

Caught signal 11 (Segmentation fault: Sent by the kernel at address (nil))
==== backtrace (tid:   3042) ====
 0 0x000000000004d212 ucs_event_set_fd_get()  ???:0
 1 0x000000000004d3dd ucs_event_set_fd_get()  ???:0
 2 0x000000000003cae0 __sigaction()  ???:0
 3 0x00000000000ac860 DisplayText.lto_priv.0()  :0
 4 0x000000000011f64e TclServiceIdle()  /usr/src/debug/tcl/tcl8.6.14/generic/tclTimer.c:751
 5 0x00000000000fbe96 Tcl_DoOneEvent()  /usr/src/debug/tcl/tcl8.6.14/generic/tclNotify.c:980
 6 0x000000000001e064 Tk_UpdateObjCmd()  :0
 7 0x000000000002f800 TclNRRunCallbacks()  /usr/src/debug/tcl/tcl8.6.14/generic/tclBasic.c:4539
 8 0x00000000000096a3 ???()  /usr/lib/python3.12/lib-dynload/_tkinter.cpython-312-x86_64-linux-gnu.so:0
 9 0x0000000000186918 _PyObject_GetMethod()  ???:0
10 0x00000000001a4b6d PyObject_Vectorcall()  ???:0
11 0x000000000018931f _PyEval_EvalFrameDefault()  ???:0
12 0x00000000001e166c PyObject_CallFinalizerFromDealloc()  ???:0
13 0x000000000018e71b _PyEval_EvalFrameDefault()  ???:0
14 0x00000000001e166c PyObject_CallFinalizerFromDealloc()  ???:0
15 0x0000000000009aac ???()  /usr/lib/python3.12/lib-dynload/_tkinter.cpython-312-x86_64-linux-gnu.so:0
16 0x000000000002f800 TclNRRunCallbacks()  /usr/src/debug/tcl/tcl8.6.14/generic/tclBasic.c:4539
17 0x00000000000317e5 TclEvalEx()  /usr/src/debug/tcl/tcl8.6.14/generic/tclBasic.c:5408
18 0x0000000000032097 Tcl_EvalEx()  /usr/src/debug/tcl/tcl8.6.14/generic/tclBasic.c:5073
19 0x0000000000016cd0 Tk_BindEvent()  /usr/src/debug/tk/tk8.6.14/unix/../generic/tkBind.c:2593
20 0x000000000001ccb3 TkBindEventProc()  ???:0
21 0x000000000002eec7 Tk_HandleEvent()  ???:0
22 0x000000000002f17d WindowEventProc()  :0
23 0x00000000000fbc68 Tcl_ServiceEvent()  /usr/src/debug/tcl/tcl8.6.14/generic/tclNotify.c:670
24 0x00000000000fbec0 Tcl_DoOneEvent()  /usr/src/debug/tcl/tcl8.6.14/generic/tclNotify.c:903
25 0x0000000000004807 ???()  /usr/lib/python3.12/lib-dynload/_tkinter.cpython-312-x86_64-linux-gnu.so:0
26 0x000000000025848a PyUnicode_RPartition()  ???:0
27 0x00000000001a4b6d PyObject_Vectorcall()  ???:0
28 0x000000000018931f _PyEval_EvalFrameDefault()  ???:0
29 0x00000000001e1c65 PyObject_CallFinalizer()  ???:0
30 0x00000000001e1708 PyObject_CallFinalizerFromDealloc()  ???:0
31 0x000000000018e71b _PyEval_EvalFrameDefault()  ???:0
32 0x000000000024d0f5 PyEval_EvalCode()  ???:0
33 0x00000000002703ea PySet_Pop()  ???:0
34 0x000000000026b2ef _PyObject_GC_Resize()  ???:0
35 0x0000000000285924 PyImport_GetMagicNumber()  ???:0
36 0x0000000000284c51 _PyRun_SimpleFileObject()  ???:0
37 0x000000000028480f _PyRun_AnyFileObject()  ???:0
38 0x000000000027d034 Py_RunMain()  ???:0
39 0x000000000023860c Py_BytesMain()  ???:0
40 0x0000000000025c88 __libc_init_first()  ???:0
41 0x0000000000025d4c __libc_start_main()  ???:0
42 0x0000000000001045 _start()  ???:0
=================================

I am on python 3.12. Everything else works perfectly fine.

After some debugging, I found that the error was from these lines.

self.log_textbox.insert(tk.END, txt, tags)
self.log_textbox.yview_moveto(1)
self.log_textbox.configure(state=tk.DISABLED)

It turns out that the TK state was switching too quickly so it caused a segfault within the self.log function. I remedied the problem by changing the log function to the code below.

    def disable_log_textbox(self):
        try:
            if self.log_textbox.winfo_exists():
                self.log_textbox.configure(state=tk.DISABLED)
        except Exception as e:
            print(f"Error disabling log_textbox: {e}")
    
    def log(self, txt: str = '', tags: list = [], where: str = 'both', link: str = '') -> None:
        """ Log to main window (where can be 'screen', 'file', or 'both') """
        if where != 'file':
            
            try:
                # Ensure this is done on the main thread
                if not self.log_textbox.winfo_exists():
                    return  # Exit if widget does not exist
                
                self.log_textbox.configure(state=tk.NORMAL)

                if link:
                    tags = tags + self.hyperlink.add(partial(self.openLink, link))
                
                
                self.log_textbox.insert(tk.END, txt, tags)
                self.log_textbox.yview_moveto(1)  # Scroll to last line
                self.log_textbox.after(0, self.disable_log_textbox)
            except Exception as e:
                print(f"Error updating log_textbox: {e}")

        if where != 'screen' and self.log_file and not self.log_file.closed:
            
            try:
                if tags == 'error':
                    txt = f'ERROR: {txt}'
                self.log_file.write(txt)
                self.log_file.flush()
            except Exception as e:
                print(f"Error writing to log file: {e}")

The disable_log_textbox function ensures that the state changes do not conflict. Since adding this code I have had no issues with the program. I am not familiar with TK so I do not know if this is the best solution. Also, I do not know if this is only a problem on Linux as no other issues seem to be similar.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions