GNOME Bugzilla – Bug 721791
Segmentation fault when correcting invalid date
Last modified: 2018-06-29 23:24:14 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/
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.
True, but let me just add this:
+ Trace 233049
$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.
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?
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.
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.
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?
Huh. I typed 50 extra digits into the year and couldn't get an assert. What did you do?
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?
(gdb) up
+ Trace 233050
$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 ;)
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.
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!
OK, try r23725. I've clamped the "year" passed in to GDateTime from struct tm to be in between 0 and 9999.
I think you have a typo in there, shouldn't that be %= instead of % in line 402?
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.