Bug 1370514 - Evolution crashes when replying to mail
Summary: Evolution crashes when replying to mail
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: evolution
Version: 24
Hardware: Unspecified
OS: Linux
unspecified
high
Target Milestone: ---
Assignee: Milan Crha
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2016-08-26 14:18 UTC by rh
Modified: 2016-09-07 10:04 UTC (History)
5 users (show)

Fixed In Version: evolution-3.21.92
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2016-09-06 16:42:14 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
abrt info -d (16.56 KB, text/plain)
2016-08-26 14:18 UTC, rh
no flags Details
core-backtrace (74.63 KB, text/plain)
2016-08-26 14:18 UTC, rh
no flags Details
Anonymized test message (27.44 KB, text/plain)
2016-08-31 17:30 UTC, Milan Crha
no flags Details
regex.c (30.67 KB, text/plain)
2016-09-02 12:34 UTC, Milan Crha
no flags Details

Description rh 2016-08-26 14:18:17 UTC
Created attachment 1194363 [details]
abrt info -d

Description of problem:
Evolution crashes when replying to a certain mail

Version-Release number of selected component (if applicable):
Evolution 3.20.5

How reproducible:
always

Steps to Reproduce:
1. Open evolution
2. Reply to the mail (received over IMAP)

Actual results:
Evolution crashes

Expected results:
Evolution opens a reply editor

Additional info:
Crash info as provided by ABRT info is attached. If you need the email source, please let me know.

Comment 1 rh 2016-08-26 14:18:47 UTC
Created attachment 1194364 [details]
core-backtrace

Comment 2 Milan Crha 2016-08-29 12:37:50 UTC
Thanks for a bug report. It seems to me that your email triggered some busy-loop issue in the /usr/lib64/libpcre.so.1.2.7. It would be helpful to have the corresponding message for testing. Make sure you'll not expose anything private. Thanks in advance.

Comment 3 rh 2016-08-30 07:56:42 UTC
Is there a way to flag this bug report as confidential / restrict access?

Comment 4 Milan Crha 2016-08-30 09:08:52 UTC
Sure, I did so (I think). You should be still able to still see the bug report, and the updates on it, because you are the reporter. In any case, if you are unsure and do not want to send the message in the wild, then feel free to send it attached only to my bugzilla email address, just name this bug report in the subject, thus I'd not overlook it in my spam folder. This way it's safer than relying of a flag which someone can uncheck accidentally.

Comment 5 rh 2016-08-31 11:12:35 UTC
Thanks, I have sent the questionable email as an attachment to your email address.

Comment 6 Milan Crha 2016-08-31 17:30:14 UTC
Created attachment 1196477 [details]
Anonymized test message

Thanks for the test message. I anonymized it and I'm also able to reproduce it when I reply or edit as new it into the Plain Text mode and choose to Lose Formatting. It seems to me that the regexp which looks for links, email addresses and such triggers some recursion, because the crash is basically about stack overflow. I can reproduce it with your message both in the 3.20.5 and in the current development version, which uses WebKit2 (the message causes crash of the WebProcess, not the UI).

The "full" backtrace looks like this:

Thread 1 "evolution" received signal SIGSEGV, Segmentation fault.
match (eptr=0x4ea0c04 "xxxxxx xxxx-xxxxx XXX: https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [XxxxXxxxxx$o] --> XXXXXXXX https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxx"..., 
    ecode=0x4e84d55 "\035&\035n\035b\035s\035p\035;x", 
    mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., 
    offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=15876) at pcre_exec.c:516
516	{

(gdb) bt

#0  0x00007fffe423e0ba in match (eptr=0x4ea0c04 "xxxxxx xxxx-xxxxx XXX: https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [XxxxXxxxxx$o] --> XXXXXXXX https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxx"..., ecode=0x4e84d55 "\035&\035n\035b\035s\035p\035;x", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=15876) at pcre_exec.c:516
#1  0x00007fffe423f086 in match (eptr=<optimized out>, ecode=0x4e84d52 "~", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:1612
#2  0x00007fffe424c662 in match (eptr=<optimized out>, ecode=0x4e84d65 "y", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:2061
#3  0x00007fffe424c662 in match (eptr=<optimized out>, ecode=0x4e84d65 "y", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:2061
...
#15873 0x00007fffe424c662 in match (eptr=<optimized out>, ecode=0x4e84d65 "y", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:2061
#15874 0x00007fffe424c662 in match (eptr=<optimized out>, ecode=0x4e84d65 "y", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:2061
#15875 0x00007fffe423fce6 in match (eptr=<optimized out>, ecode=0x4e84d4e "\222\203", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:1878
#15876 0x00007fffe42408e3 in match (eptr=<optimized out>, ecode=0x4e84d49 "\205", mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:983

#15877 0x00007fffe4250591 in pcre_exec (argument_re=0x4e84c20, extra_data=<optimized out>, subject=<optimized out>, length=26884, start_offset=0, options=9216, offsets=0x4e11010, offsetcount=9) at pcre_exec.c:6936
#15878 0x00007ffff352b4eb in g_match_info_next () at /lib64/libglib-2.0.so.0
#15879 0x00007ffff352cd9f in g_regex_match_full () at /lib64/libglib-2.0.so.0
#15880 0x00007ffff352d84c in g_regex_replace_eval () at /lib64/libglib-2.0.so.0

#15881 0x00007ffff77ea7b9 in parse_html_into_blocks (view=0x364c770, document=0x4e62050, parent=0x7fffc81cfce0, passed_block_template=0x0, html=0x4e96350 "Xx xxxx xx xxxxxx. Xxx Xxxxxxxxxxx xxxx xxx xxx xx xxx Xxxxxxxxx ", 'x' <repeats 11 times>, " xxxxxxxxüxxx.<br>Xxx XXX xxx: https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx<br>Xxxxxxxx xxx xxx xxx Xxxx"...) at e-html-editor-view.c:7485
#15882 0x00007ffff77ecb24 in html_editor_convert_view_content (view=0x364c770, preferred_text=0x0) at e-html-editor-view.c:8249
#15883 0x00007ffff77f56e5 in html_editor_view_load_status_changed (view=0x364c770) at e-html-editor-view.c:10860
#15884 0x00007ffff37ee3e8 in g_closure_invoke () at /lib64/libgobject-2.0.so.0
#15885 0x00007ffff3800442 in signal_emit_unlocked_R () at /lib64/libgobject-2.0.so.0
#15886 0x00007ffff380908c in g_signal_emit_valist () at /lib64/libgobject-2.0.so.0
#15887 0x00007ffff380945f in g_signal_emit () at /lib64/libgobject-2.0.so.0
#15888 0x00007ffff37f27b4 in g_object_dispatch_properties_changed () at /lib64/libgobject-2.0.so.0
#15889 0x00007ffff37f4cc4 in g_object_notify () at /lib64/libgobject-2.0.so.0
#15890 0x00007ffff5253adf in WebCore::FrameLoader::checkLoadCompleteForThisFrame() () at /lib64/libwebkitgtk-3.0.so.0
#15891 0x00007ffff5253cb7 in WebCore::FrameLoader::checkLoadComplete() () at /lib64/libwebkitgtk-3.0.so.0
#15892 0x00007ffff523dd38 in WebCore::DocumentLoader::finishedLoading(double) () at /lib64/libwebkitgtk-3.0.so.0
#15893 0x00007ffff523ec0c in WebCore::DocumentLoader::continueAfterContentPolicy(WebCore::PolicyAction) () at /lib64/libwebkitgtk-3.0.so.0
#15894 0x00007ffff523fcc4 in WebCore::DocumentLoader::responseReceived(WebCore::CachedResource*, WebCore::ResourceResponse const&) () at /lib64/libwebkitgtk-3.0.so.0
#15895 0x00007ffff5239f77 in WebCore::DocumentLoader::handleSubstituteDataLoadNow(WebCore::Timer<WebCore::DocumentLoader>*) () at /lib64/libwebkitgtk-3.0.so.0
#15896 0x00007ffff4bfad5f in WebCore::ThreadTimers::sharedTimerFiredInternal() () at /lib64/libwebkitgtk-3.0.so.0
#15897 0x00007ffff4c1ee32 in WebCore::sharedTimerTimeoutCallback(void*) () at /lib64/libwebkitgtk-3.0.so.0
#15898 0x00007ffff351a273 in g_timeout_dispatch () at /lib64/libglib-2.0.so.0
#15899 0x00007ffff3519803 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0
#15900 0x00007ffff3519bb0 in g_main_context_iterate.isra () at /lib64/libglib-2.0.so.0
#15901 0x00007ffff3519ed2 in g_main_loop_run () at /lib64/libglib-2.0.so.0
#15902 0x00007ffff3fd2825 in gtk_main () at gtkmain.c:1269
#15903 0x0000000000403de6 in main (argc=1, argv=0x7fffffffdcf8) at main.c:660


This is taken from the 3.18.5, because it is easier. The frames between #3 and #15873 all look the same, just like the #3 or the #15873.

Comment 7 Milan Crha 2016-08-31 17:33:00 UTC
Tomas, could you check our regular expressions, please? Maybe we've there something odd. If you do not find, then we can move this to the pcre package, where the recursion happens.

For the record:

(gdb) f 3
#3  0x00007fffe424c662 in match (eptr=<optimized out>, ecode=0x4e84d65 "y", 
    mstart=0x4e9ce03 "https://xxxxxxxx.xxxx.xx:oooo/XxxxxXxxxxxx/Xxxxxxxx/Xxxxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.XxxxxxxxXxxxxxxx] Xxxxxxxxxxx XXX xxxxxxxx xxxxxxxxx oooo-oo-oo oo:oo:oo oooo [xxxoxxxxxxx.Xxxxxxx"..., 
    offset_top=4, md=0x7fffffffca00, eptrb=0x0, rdepth=<optimized out>) at pcre_exec.c:2061
2061	      RMATCH(eptr, prev, offset_top, md, eptrb, RM13);
(gdb) l
2056	      ecode = prev;
2057	      goto TAIL_RECURSE;
2058	      }
2059	    else  /* OP_KETRMAX */
2060	      {
2061	      RMATCH(eptr, prev, offset_top, md, eptrb, RM13);
2062	      if (rrc == MATCH_ONCE && md->once_target == prev) rrc = MATCH_NOMATCH;
2063	      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
2064	      if (*prev == OP_ONCE)
2065	        {
(gdb)

Comment 8 Tomas Popela 2016-09-02 09:49:44 UTC
I don't see anything obvious, thus moving to pcre.

Comment 9 Petr Pisar 2016-09-02 11:18:31 UTC
It looks like exhausted stack. Some regular expressions on some inputs have pathological backtracking path that leads to enormous recursion and your default 8 MB large stack gets exhausted. This is feature of stack-based recursive algorithms and PCRE can do with.

You can either rewrite your regular expression to use less recursion (less greedy and less possessive atoms), or you can limit the recursion depth by setting match_limit_recursion member of pcre_exec() second argument, or you can increase stack size of your process.

I recommend you to read pcrestack(3) manual page and to use pcretest tool for debugging your regular expression with your input. Unfortunately, you did not provide any of them in this bug report.

Comment 10 Milan Crha 2016-09-02 12:34:00 UTC
Created attachment 1197148 [details]
regex.c

Here's a simple reproducer, which makes it crash on the stack overflow out of the evolution code. The first line of the file shows how to compile and run it.

Comment 11 Petr Pisar 2016-09-06 08:00:43 UTC
It starts segfaulting with 14085 KB stack in Fedora 26. But it segfaults randomly. On Fedora 23, it does not segfault, but it also prints "---(null)---". Something different from Fedora 26 where it prints the input.

I thought it's because of newer pcre. But F26 and F23 have the same pcre package. So I thought it's because of newer GCC having more aggressive optimization or bigger stack frames. But your reproducer uses glib2 functions. Not pcre functions directly. And glib2 package version also differs and indeed rebuilding F23 glib2 in F26 provides the same F23 experience -- no crash, no string printed.

I will have to nail down the reproducer to pcre only.

Comment 12 Petr Pisar 2016-09-06 12:42:52 UTC
That's because F23 glib2 bundles pcre-8.31.

Comment 13 Petr Pisar 2016-09-06 16:01:05 UTC
I can reproduce it with pcre only. It happens when matching the input from offset 180.

It's because of the second expression part "((?:(?!&nbsp;).)*)". It consumes a lot of stack because the greedy * operator recurses on each character for a case when some other expression part failed. And because the recursion happens on each character of the input, the stack exhaustion exhibits on very long lines like in your reproducer (there is a 25908-character long line, that's 25908 recursions, each consumes about 500 B of a stack, that agrees with the observed 14-MB limit.).

Solution is to make the * operator possesive by changing it into "*+" operator. It changes the preceding group into an atomic group which must match the longest sequence of the content of the group. In other words it says to pcre that it does not need to examine substrings of non-"&nbsp;"-character string.

If you want to know more, read "ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS" section in pcrepattern(3) manual page.

Try changing two lines in the reproducer into:

#define URL_PATTERN_BASE "(?=((?:(?:(?:" URL_PROTOCOLS ")\\:\\/\\/)|(?:www\\.|ftp\\.))[^\\s\\/\\$\\.\\?#].[^\\s]*+)"
#define URL_PATTERN_NO_NBSP ")((?:(?!&nbsp;).)*+)"

It adds "+" after the "*" on two places.

Comment 14 Milan Crha 2016-09-06 16:36:24 UTC
Thanks a lot for all the investigation. I changed the regex locally and I do not see any difference, except of surviving evolution, instead of crashing. The evolution also uses an email pattern:

  /* http://www.w3.org/TR/html5/forms.html#valid-e-mail-address */
  #define E_MAIL_PATTERN \
	"[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}"\
	"[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*"

To which I'll add the '+' too, just in case.

By the way, would not it be a regression in pcre that 8.31 works, but 8.39 crashes?

Comment 15 Milan Crha 2016-09-06 16:42:14 UTC
I'm making this bug public, there is nothing private after all.

Created commit 4163018 in evo master (3.21.92+) [1]

[1] https://git.gnome.org/browse/evolution/commit/?id=4163018

Comment 16 Petr Pisar 2016-09-07 06:45:42 UTC
The old glib2 with bundled pcre does not crash. But also does not return correct result. I don't know why. I tried the pure pcre reproducer against Fedora's pcre-8.31 and it crashed.

Comment 17 Milan Crha 2016-09-07 10:04:24 UTC
(In reply to Petr Pisar from comment #16)
> The old glib2 with bundled pcre does not crash. But also does not return
> correct result. I don't know why. I tried the pure pcre reproducer against
> Fedora's pcre-8.31 and it crashed.

Aha, good... I mean... :)


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