After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 721791 - Segmentation fault when correcting invalid date
Segmentation fault when correcting invalid date
Status: RESOLVED FIXED
Product: GnuCash
Classification: Other
Component: User Interface General
2.6.0
Other Linux
: Normal normal
: ---
Assigned To: gnucash-ui-maint
gnucash-ui-maint
Depends on:
Blocks:
 
 
Reported: 2014-01-08 14:25 UTC by Lorenz
Modified: 2018-06-29 23:24 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Stacktrace (8.89 KB, text/plain)
2014-01-08 14:25 UTC, Lorenz
Details
Stacktrace for failing assertion (12.30 KB, text/plain)
2014-01-18 23:24 UTC, Lorenz
Details

Description Lorenz 2014-01-08 14:25:43 UTC
Created attachment 265705 [details]
Stacktrace

I am using gnucash 1:2.6.0-1 from Debian Unstable.
I have been able to reproduce this segmentation fault every time.

Steps to reproduce:
1. Go to an account detail page
2. At the bottom, append a digit (e.g. 2) to the end of the date, making it the year 20142
3. Press backspace to correct your error

A stacktrace is attached and also available at http://bpaste.net/show/c0VEHzhfvDrxewwTZgac/
Comment 1 John Ralls 2014-01-17 05:38:14 UTC
I'm not able to replicate this on Debian Testing. Please contact the Debian package maintainer and obtain his assistance to isolate the problem a bit more.
Note from the stack trace that the crash is coming from the C library, not Gnucash.
Comment 2 Lorenz 2014-01-17 15:52:48 UTC
True, but let me just add this:

  • #5 qof_strftime
    at gnc-date.c line 1381
$13 = (gchar *) 0x7fffffffca70 "\004"
(gdb) ins max
$14 = 1024
(gdb) ins tm
$15 = (const struct tm *) 0x7fffffffca30
(gdb) ins *tm
$16 = {tm_sec = 44496064, tm_min = 0, tm_hour = 0, tm_mday = 0, tm_mon = 44496064, tm_year = 0, tm_wday = 7792008, tm_yday = 0, tm_isdst = 4, tm_gmtoff = 7792000, tm_zone = 0x76e580 ""}

This is always filled with different stuff on each run of gnucash, here's a sample:
$1 = {tm_sec = 38681568, tm_min = 0, tm_hour = 0, tm_mday = 0, tm_mon = 38681568, tm_year = 0, tm_wday = 7789992, tm_yday = 0, tm_isdst = 4, tm_gmtoff = 7789984, tm_zone = 0x76dda0 ""}
$1 = {tm_sec = 0, tm_min = 0, tm_hour = 0, tm_mday = 0, tm_mon = 0, tm_year = 0, tm_wday = 6455584, tm_yday = 0, tm_isdst = -13432, tm_gmtoff = 3367254360064, tm_zone = 0x77d2a0 "@\203_\002"}

I'm not terribly sure whether that is the intended value range... So it may be that bad data is being passed to the C library? The segfaulting strlen is called in the following line:

cpy (STRLEN (f_wkday), f_wkday);
(in eglibc-2.17 from debian unstable, that's line 781 of time/strftime_l.c as shown in the traceback). Given that

# define f_wkday ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))

and that the weekday value in the time struct that is being passed to strftime is completely bonkers, I'd say the problem probably isn't with eglibc? I hope I'm not completely off track, but with the sources loaded into gdb, we can see that f_wkday (intended to be a short representation of the Weekday like "Sun" or "Mon") is actually NULL, and looking at the _NL_CURRENT's definition:

current->values[((int) (_NL_WDAY_1 + tp->tm_wday) & 0xffff)].string

...makes sense because we're accessing some huge index in the current locale (current is loc->__locales[LC_TIME]). This index has taken values like 58819 or 56803 for me, which don't really exist in a locale (see the above values in the time struct).



Retracing the origin of this bogus time stuff leads to gnc_split_register_get_date_help in register/ledger-core/split-register-model.c:922, where the timestamp 573454339200 is extracted from the Cell, which is Wed, 17 Jan 20142 00:00:00 GMT. The problem then seems to be the call to gnc_localtime_r which writes the bogus info into the struct. That's as far as I traced it.

I hope this helps.
Comment 3 John Ralls 2014-01-18 16:51:04 UTC
Ah, I see the problem:  g_date_time_new_from_unix_local() is returning NULL for that time64. Since in gnc_split_register_get_date_help the struct tm isn't explicitly zeroed and since the gnc_localtime_r's return value is ignored, it's passing the randomly-bogus struct tm on to (eventually) strftime, which quite reasonably pukes.

So I guess the interesting question is why does it work on Testing?
Comment 4 John Ralls 2014-01-18 19:58:26 UTC
And the answer is that strftime on Testing truncates the year value and returns 2014 instead of 20142, so the Timeval extracted from the cell is sane.

I guess somebody "fixed" that, exposing this bug.
Comment 5 John Ralls 2014-01-18 21:52:09 UTC
I just committed r23706, which should fix the immediate problem. Please test it and also tab out of the date field with the bad date in it and make sure that it doesn't crash and does change the year to something sane.
Comment 6 Lorenz 2014-01-18 22:57:36 UTC
Yep, fixed. Thank you very much!

However, ... if I keep typing in several more digits:
GLib:ERROR:/tmp/buildd/glib2.0-2.36.4/./glib/gdatetime.c:1519:g_date_time_get_ymd: assertion failed: (leap == GREGORIAN_LEAP(the_year))

This is a separate bug, however. And it really only occurs if someone really wants to make gnucash crash (like I did :P)

So, I'll mark this as fixed then?
Comment 7 John Ralls 2014-01-18 23:08:50 UTC
Huh. I typed 50 extra digits into the year and couldn't get an assert. What did you do?
Comment 8 Lorenz 2014-01-18 23:24:51 UTC
Created attachment 266637 [details]
Stacktrace for failing assertion

The year 20141234 did the trick for me. I attached a traceback, but maybe this should be a separate bug?

This occurs both on the version in Debian unstable and on trunk.

Note this:
(gdb) ins *(GDateTime*) 0x29d8460
$3 = {usec = 0, tz = 0x2a5f300, interval = 0, days = -1233500280, ref_count = 1}

It seems to me that there is an overflow in the number of days happening. Indeed, 20141234*365 = 7351550410, which, as a signed 32-bit integer, is roughly -1238384182 or only some 5 million days off (ahem, it's just a rough estimate). A wild guess, but maybe the overflowing day counter is the problem here?
Comment 9 Lorenz 2014-01-18 23:35:20 UTC
(gdb) up
  • #8 gnc_parse_date
    at datecell-gnome.c line 149
$8 = 0x2a5d9e0 "18.01.20141234"
(gdb) ins parsed
$9 = (struct tm *) 0x2545318
(gdb) ins *parsed
$10 = {tm_sec = 0, tm_min = 0, tm_hour = 0, tm_mday = 18, tm_mon = 0, tm_year = 20139334, tm_wday = -5, tm_yday = 18, tm_isdst = -1, tm_gmtoff = 0, tm_zone = 0x0}

Maybe this helps? The year in the struct tm is exactly 1900 years less than what I entered, so that's correct. And that reduces the difference to the value in the GDateTime to some 540,000 days (assuming 365.25 days per year), which are still 1500 years, but eh ;)
Comment 10 John Ralls 2014-01-19 03:12:10 UTC
Oh, the assert was after hitting tab. Maybe that's why I didn't hit it.

Even if GDate didn't barf, GDateTime will have trouble with anything outside of 0 - 9999, so I'll just prevent a date outside that range from escaping the GUI.
Comment 11 Lorenz 2014-01-19 08:39:28 UTC
No, no tab pressed. It fails when I enter the last 4, see #9 in the traceback:
change=change@entry=0x29cffd0 "4", change_len=change_len@entry=1, newval=newval@entry=0x2a5d9e0 "18.01.20141234"

Thanks again for looking into it!
Comment 12 John Ralls 2014-01-20 01:56:32 UTC
OK, try r23725. I've clamped the "year" passed in to GDateTime from struct tm to be in between 0 and 9999.
Comment 13 Lorenz 2014-01-20 15:09:56 UTC
I think you have a typo in there, shouldn't that be %= instead of % in line 402?
Comment 14 John Ralls 2018-06-29 23:24:14 UTC
GnuCash bug tracking has moved to a new Bugzilla host. This bug has been copied to https://bugs.gnucash.org/show_bug.cgi?id=721791. Please update any external references or bookmarks.