Subject: bug#46791: 27.1; crash at gtk_label_new()

From: Eli Zaretskii <[email-masked]>
Date: Fri, 26 Feb 2021 16:37:03 +0200

> Date: Fri, 26 Feb 2021 16:32:06 +0900 (JST)
> From: YASUOKA Masahiko <[email-masked]>
> 
> When I'm using Mew(https://mew.org/) on emacs 27.1, emacs crashes
> frequently.  It happens when I am composing a mail message in "draft
> mode" of Mew.
> [...]
> In src/gtkutil.c, update_frame_tool_bar():
> 
>     5197           ti = xg_make_tool_item (f, w, &wbutton, label, i, horiz, text_image);
> 
> this "label" is invalid when the crash happens.  This "label" 
> 
>     5006   for (i = j = 0; i < f->n_tool_bar_items; ++i)
>     5007     {
>     5008       bool enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
>     5009       bool selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
> 
>     5022       const char *label
>     5023         = (EQ (style, Qimage) || (vert_only && horiz)) ? NULL
>     5024         : STRINGP (PROP (TOOL_BAR_ITEM_LABEL))
>     5025         ? SSDATA (PROP (TOOL_BAR_ITEM_LABEL))
>     5026         : "";
> 
> is set at the begining of the loop(#5006),
> 
>     5065       specified_file = file_for_image (image);
>     5066       if (!NILP (specified_file) && !NILP (Ffboundp (Qx_gtk_map_stock)))
>     5067         stock = call1 (Qx_gtk_map_stock, specified_file);
>     5068
> 
> it sometimes become invalid just after #5067.  Then it is passed to
> gtk_label_new() through xg_make_tool_item(), the crash will happen.
> 
> Since we can get a valid "label" pointer again by setting it in the
> same way of the beginning of the loop, we can fix the bug by moving
> the initialization of "label" to a place just before it is used.  The
> following diff does this:

Thanks.  Could you please try the slightly different patch below?  It
is IMO safer, since it doesn't depend on a 'char *' pointer into a
Lisp string's data to remain valid after some point in the code.

diff --git a/src/gtkutil.c b/src/gtkutil.c
index d824601..825fbe1 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -5019,11 +5019,10 @@ update_frame_tool_bar (struct frame *f)
       GtkWidget *wbutton = NULL;
       Lisp_Object specified_file;
       bool vert_only = ! NILP (PROP (TOOL_BAR_ITEM_VERT_ONLY));
-      const char *label
-	= (EQ (style, Qimage) || (vert_only && horiz)) ? NULL
-	: STRINGP (PROP (TOOL_BAR_ITEM_LABEL))
-	? SSDATA (PROP (TOOL_BAR_ITEM_LABEL))
-	: "";
+      Lisp_Object label
+	= (EQ (style, Qimage) || (vert_only && horiz))
+	? Qnil
+	: PROP (TOOL_BAR_ITEM_LABEL);
 
       ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j);
 
@@ -5136,8 +5135,11 @@ update_frame_tool_bar (struct frame *f)
 
       /* If there is an existing widget, check if it's stale; if so,
 	 remove it and make a new tool item from scratch.  */
-      if (ti && xg_tool_item_stale_p (wbutton, stock_name, icon_name,
-				      img, label, horiz))
+      if (ti && xg_tool_item_stale_p (wbutton, stock_name, icon_name, img,
+				      NILP (label)
+				      ? NULL
+				      : STRINGP (label) ? SSDATA (label) : "",
+				      horiz))
 	{
 	  gtk_container_remove (GTK_CONTAINER (wtoolbar),
 				GTK_WIDGET (ti));
@@ -5194,7 +5196,11 @@ update_frame_tool_bar (struct frame *f)
 #else
 	  if (w) gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
 #endif
-          ti = xg_make_tool_item (f, w, &wbutton, label, i, horiz, text_image);
+          ti = xg_make_tool_item (f, w, &wbutton,
+				  NILP (label)
+				  ? NULL
+				  : STRINGP (label) ? SSDATA (label) : "",
+				  i, horiz, text_image);
           gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j);
         }