GnuCash
Contact   Instructions
Bug 798188 - The Invoice Editor -> Printable Invoice toolbar button crashes on Windows
Summary: The Invoice Editor -> Printable Invoice toolbar button crashes on Windows
Status: VERIFIED FIXED
Alias: None
Product: GnuCash
Classification: Unclassified
Component: User Interface General (show other bugs)
Version: git-maint
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: ui
QA Contact: ui
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-05-16 09:40 EDT by Christopher Lam
Modified: 2021-05-22 12:14 EDT (History)
5 users (show)

See Also:


Attachments
like this? (1.48 KB, patch)
2021-05-17 06:26 EDT, Christopher Lam
no flags Details

Description Christopher Lam 2021-05-16 09:40:07 EDT
The Invoice Editor has toolbar button to generate printable invoice report.

The new feature to reuse existing invoice report seems to crash on Windows.

To reproduce (on Windows):
- Open Invoice Editor
- Create dummy invoice
- Click "Print Invoice" button
- Close the invoice report just generated
- Click "Print Invoice" again

Result: crash
Comment 1 Christopher Lam 2021-05-16 09:40:33 EDT
The same logic exists for the budget editor -> budget report toolbar button.
Comment 2 Christopher Lam 2021-05-16 10:09:04 EDT
Hint: d6082e1a60da5179a9309ccccb96f5c26014d895

void
gnc_invoice_window_printCB (GtkWindow* parent, gpointer data)
{
    InvoiceWindow *iw = data;

    if (iw->reportPage && GNC_IS_PLUGIN_PAGE (iw->reportPage))
        gnc_plugin_page_report_reload (GNC_PLUGIN_PAGE_REPORT (iw->reportPage));
    else
        iw->reportPage = gnc_invoice_window_print_invoice
            (parent, iw_get_invoice (iw));

    gnc_main_window_open_page (GNC_MAIN_WINDOW (iw->dialog), iw->reportPage);
}

The only conclusion I can draw is that GNC_IS_PLUGIN_PAGE (iw->reportPage) will return TRUE on Windows and FALSE on Linux, if the iw->reportPage has been closed. But not sure how to fix this.
Comment 3 John Ralls 2021-05-16 11:52:09 EDT
Do you have a stack trace showing that it's actually getting to gnc_plugin_page_reload? I think it more likely that the crash is in g_type_check_instance_type(), the function that underlies GNC_IS_PLUGIN_PAGE, trying to access freed memory.

The else clause in your commit saves a pointer to allocated memory without reffing it and without any way of detecting that it's been freed. Use either g_object_ref to keep the report page from being freed or g_object_weak_ref to automatically NULL iw->reportPage when it is destroyed. Note that in the first case you need to call g_object_unref(iw->reportPage) in gnc_invoice_window_destroy_cb so that reportPage isn't leaked.

See https://developer.gnome.org/gobject/stable/gobject-memory.html
Comment 4 Christopher Lam 2021-05-17 06:26:47 EDT
Created attachment 374072 [details]
like this?

(doesn't work)

* 18:05:40 ERROR <gnc.html> gnc_html_reload: assertion 'self != NULL' failed
* 18:05:40 ERROR <gnc.report.core> gnc_run_report_with_error_handling: assertion '!scm_is_false (report)' failed
munmap_chunk(): invalid pointer
./run-maint.sh: line 10: 57341 Aborted                 (core dumped) ./gnucash --extra --logto stdout
Comment 5 Christopher Lam 2021-05-17 08:53:47 EDT
I think you're right i 
valgrind output:

==60781== Invalid read of size 8
==60781==    at 0x4F29882: gnc_invoice_window_printCB (dialog-invoice.c:837)
==60781==    by 0x4F7D841: gnc_plugin_page_invoice_cmd_print (gnc-plugin-page-invoice.c:1042)
==60781==    by 0x5B998F9: g_closure_invoke (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BAC4B2: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2C60: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2DC2: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x528B814: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2404.19)
==60781==    by 0x552F92C: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2404.19)
==60781==    by 0x5B99B55: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2BDE: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2DC2: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x53149DF: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2404.19)
==60781==  Address 0x151ae590 is 224 bytes inside a block of size 280 free'd
==60781==    at 0x483D948: free (in /gnu/store/7dmfnzh4yvfcbsdb1ik456zp27r1acka-valgrind-3.16.1/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==60781==    by 0x5BB99A3: g_type_free_instance (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x511FA60: gnc_main_window_close_page (gnc-main-window.c:3330)
==60781==    by 0x5B99B55: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2BDE: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2DC2: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x53149DF: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2404.19)
==60781==    by 0x5B99B55: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2BDE: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BB2DC2: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5312C13: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2404.19)
==60781==    by 0x55DACFE: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2404.19)
==60781==  Block was alloc'd at
==60781==    at 0x483C79B: malloc (in /gnu/store/7dmfnzh4yvfcbsdb1ik456zp27r1acka-valgrind-3.16.1/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==60781==    by 0x4C4C698: g_malloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6600.1)
==60781==    by 0x4C64CF1: g_slice_alloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6600.1)
==60781==    by 0x4C6536D: g_slice_alloc0 (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6600.1)
==60781==    by 0x5BB964B: g_type_create_instance (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5B9F077: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x4FAB2E2: gnc_plugin_page_report_constructor (gnc-plugin-page-report.c:1170)
==60781==    by 0x5B9F1E5: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BA102B: g_object_new_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x5BA138C: g_object_new (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.6600.1)
==60781==    by 0x4FABB01: gnc_plugin_page_report_new (gnc-plugin-page-report.c:1322)
==60781==    by 0x4F297F1: gnc_invoice_window_print_invoice (dialog-invoice.c:819)
Comment 6 John Ralls 2021-05-17 12:02:49 EDT
(In reply to Christopher Lam from comment #4)
> Created attachment 374072 [details]
> like this?
> 
> (doesn't work)
> 
> * 18:05:40 ERROR <gnc.html> gnc_html_reload: assertion 'self != NULL' failed
> * 18:05:40 ERROR <gnc.report.core> gnc_run_report_with_error_handling:
> assertion '!scm_is_false (report)' failed
> munmap_chunk(): invalid pointer
> ./run-maint.sh: line 10: 57341 Aborted                 (core dumped)
> ./gnucash --extra --logto stdout

Yes, like that, but you also need to make sure that the report page pays attention to the reference count. A lot of GnuCash's UI objects don't.
Comment 7 Christopher Lam 2021-05-18 11:04:17 EDT
(In reply to John Ralls from comment #6)
> Yes, like that, but you also need to make sure that the report page pays
> attention to the reference count. A lot of GnuCash's UI objects don't.

This is beyond my skills. If this is not fixed soon, then I'd disable the feature to save reportPage into the budget/invoice. It's never nice to have a reliable hard crash in Windows.
Comment 8 John Ralls 2021-05-18 12:12:28 EDT
It's not a feature if it crashes, so by all means revert d6082e1a if you don't want to put the effort into making it correct.

It's not beyond your skills. It may be beyond your understanding of the code and your motivation to gain that understanding.
Comment 9 Bob 2021-05-18 15:27:50 EDT
Just a thought, why don't you set up a callback for the page removed signal so that you can make iw->reportPage = NULL when it is removed;

Have no tested and not looked at code so may be way of on this.
Comment 10 Bob 2021-05-18 16:32:02 EDT
Thinking about that, remove may not work as you will probably get one when you move the page to another window so destroy/close maybe better if there is one.
Comment 11 Christopher Lam 2021-05-18 21:25:46 EDT
https://github.com/Gnucash/gnucash/pull/1007 candidate fix
Comment 12 John Ralls 2021-05-18 22:57:24 EDT
(In reply to Christopher Lam from comment #11)
> https://github.com/Gnucash/gnucash/pull/1007 candidate fix

Not yet.
Comment 13 Christopher Lam 2021-05-22 12:14:14 EDT
confirmed fixed in windows \o/

Note You need to log in before you can comment on or make changes to this bug.