comparison pidgin/gtkconv.c @ 32156:1693114a2655

applied changes from 6cf1aee8ac5e3c836af832eaf26ccedd611dc70b through e802003adbf0be4496de3de8ac03b47c1e471d00 Original commit message: Start looking at the GError parameter every time we call these functions: - gdk_pixbuf_loader_write - gdk_pixbuf_loader_close - gdk_pixbuf_new_from_file - gdk_pixbuf_new_from_file_at_size - gdk_pixbuf_new_from_file_at_scale There are times when gdkpixbuf returns a semi-invalid GdkPixbuf object and also sets the GError. If this happens we want to discard and ignore the GdkPixbuf object because it can cause problems. For example, calling gdk_pixbuf_scale_simple() causes gdkpixbuf to rapidly consume memory in an infinite loop. And that's bad. This commit adds some helper functions to gtkutils.[c|h] that make it a little easier to check the GError value. We should use them everywhere we call any of the above functions.
author Mark Doliner <mark@kingant.net>
date Wed, 22 Jun 2011 07:09:42 +0000
parents 5ffd5582f5fe
children 47c604efed32
comparison
equal deleted inserted replaced
32155:5ffd5582f5fe 32156:1693114a2655
6406 pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile, 6406 pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile,
6407 const guchar *data, gsize size) 6407 const guchar *data, gsize size)
6408 { 6408 {
6409 PidginConversation *gtkconv; 6409 PidginConversation *gtkconv;
6410 GtkIMHtmlSmiley *smiley; 6410 GtkIMHtmlSmiley *smiley;
6411 GdkPixbufLoader *loader;
6412 const char *sml; 6411 const char *sml;
6412 GError *error = NULL;
6413 6413
6414 sml = purple_account_get_protocol_name(conv->account); 6414 sml = purple_account_get_protocol_name(conv->account);
6415 gtkconv = PIDGIN_CONVERSATION(conv); 6415 gtkconv = PIDGIN_CONVERSATION(conv);
6416 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile); 6416 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile);
6417 6417
6420 6420
6421 smiley->data = g_realloc(smiley->data, smiley->datasize + size); 6421 smiley->data = g_realloc(smiley->data, smiley->datasize + size);
6422 g_memmove((guchar *)smiley->data + smiley->datasize, data, size); 6422 g_memmove((guchar *)smiley->data + smiley->datasize, data, size);
6423 smiley->datasize += size; 6423 smiley->datasize += size;
6424 6424
6425 loader = smiley->loader; 6425 if (!smiley->loader)
6426 if (!loader)
6427 return; 6426 return;
6428 6427
6429 gdk_pixbuf_loader_write(loader, data, size, NULL); 6428 if (!gdk_pixbuf_loader_write(smiley->loader, data, size, &error) || error) {
6429 purple_debug_warning("gtkconv", "gdk_pixbuf_loader_write() "
6430 "failed with size=%zu: %s\n", size,
6431 error ? error->message : "(no error message)");
6432 if (error)
6433 g_error_free(error);
6434 /* We must stop using the GdkPixbufLoader because trying to load
6435 certain invalid GIFs with at least gdk-pixbuf 2.23.3 can return
6436 a GdkPixbuf that will cause some operations (like
6437 gdk_pixbuf_scale_simple()) to consume memory in an infinite loop.
6438 But we also don't want to set smiley->loader to NULL because our
6439 code might expect it to be set. So create a new loader. */
6440 g_object_unref(G_OBJECT(smiley->loader));
6441 smiley->loader = gdk_pixbuf_loader_new();
6442 }
6430 } 6443 }
6431 6444
6432 static void 6445 static void
6433 pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile) 6446 pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile)
6434 { 6447 {
6435 PidginConversation *gtkconv; 6448 PidginConversation *gtkconv;
6436 GtkIMHtmlSmiley *smiley; 6449 GtkIMHtmlSmiley *smiley;
6437 GdkPixbufLoader *loader;
6438 const char *sml; 6450 const char *sml;
6451 GError *error = NULL;
6439 6452
6440 g_return_if_fail(conv != NULL); 6453 g_return_if_fail(conv != NULL);
6441 g_return_if_fail(smile != NULL); 6454 g_return_if_fail(smile != NULL);
6442 6455
6443 sml = purple_account_get_protocol_name(conv->account); 6456 sml = purple_account_get_protocol_name(conv->account);
6445 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile); 6458 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile);
6446 6459
6447 if (!smiley) 6460 if (!smiley)
6448 return; 6461 return;
6449 6462
6450 loader = smiley->loader; 6463 if (!smiley->loader)
6451
6452 if (!loader)
6453 return; 6464 return;
6454 6465
6455
6456
6457 purple_debug_info("gtkconv", "About to close the smiley pixbuf\n"); 6466 purple_debug_info("gtkconv", "About to close the smiley pixbuf\n");
6458 6467
6459 gdk_pixbuf_loader_close(loader, NULL); 6468 if (!gdk_pixbuf_loader_close(smiley->loader, &error) || error) {
6460 6469 purple_debug_warning("gtkconv", "gdk_pixbuf_loader_close() "
6470 "failed: %s\n",
6471 error ? error->message : "(no error message)");
6472 if (error)
6473 g_error_free(error);
6474 /* We must stop using the GdkPixbufLoader because if we tried to
6475 load certain invalid GIFs with all current versions of GDK (as
6476 of 2011-06-15) then it's possible the loader will contain data
6477 that could cause some operations (like gdk_pixbuf_scale_simple())
6478 to consume memory in an infinite loop. But we also don't want
6479 to set smiley->loader to NULL because our code might expect it
6480 to be set. So create a new loader. */
6481 g_object_unref(G_OBJECT(smiley->loader));
6482 smiley->loader = gdk_pixbuf_loader_new();
6483 }
6461 } 6484 }
6462 6485
6463 static void 6486 static void
6464 pidgin_conv_send_confirm(PurpleConversation *conv, const char *message) 6487 pidgin_conv_send_confirm(PurpleConversation *conv, const char *message)
6465 { 6488 {
6955 PidginConversation *gtkconv; 6978 PidginConversation *gtkconv;
6956 PidginWindow *win; 6979 PidginWindow *win;
6957 6980
6958 PurpleBuddy *buddy; 6981 PurpleBuddy *buddy;
6959 6982
6960 GdkPixbufLoader *loader;
6961 GdkPixbufAnimation *anim;
6962 GError *err = NULL;
6963
6964 PurpleStoredImage *custom_img = NULL; 6983 PurpleStoredImage *custom_img = NULL;
6965 gconstpointer data = NULL; 6984 gconstpointer data = NULL;
6966 size_t len; 6985 size_t len;
6967 6986
6968 GdkPixbuf *buf; 6987 GdkPixbuf *buf;
7036 } 7055 }
7037 } 7056 }
7038 7057
7039 if (data == NULL) { 7058 if (data == NULL) {
7040 icon = purple_conv_im_get_icon(PURPLE_CONV_IM(conv)); 7059 icon = purple_conv_im_get_icon(PURPLE_CONV_IM(conv));
7041
7042 if (icon == NULL) 7060 if (icon == NULL)
7043 { 7061 {
7044 gtk_widget_set_size_request(gtkconv->u.im->icon_container, 7062 gtk_widget_set_size_request(gtkconv->u.im->icon_container,
7045 -1, BUDDYICON_SIZE_MIN); 7063 -1, BUDDYICON_SIZE_MIN);
7046 return; 7064 return;
7047 } 7065 }
7048 7066
7049 data = purple_buddy_icon_get_data(icon, &len); 7067 data = purple_buddy_icon_get_data(icon, &len);
7050
7051 if (data == NULL) 7068 if (data == NULL)
7052 { 7069 {
7053 gtk_widget_set_size_request(gtkconv->u.im->icon_container, 7070 gtk_widget_set_size_request(gtkconv->u.im->icon_container,
7054 -1, BUDDYICON_SIZE_MIN); 7071 -1, BUDDYICON_SIZE_MIN);
7055 return; 7072 return;
7056 } 7073 }
7057 } 7074 }
7058 7075
7059 loader = gdk_pixbuf_loader_new(); 7076 gtkconv->u.im->anim = pidgin_pixbuf_anim_from_data(data, len);
7060 gdk_pixbuf_loader_write(loader, data, len, NULL);
7061 gdk_pixbuf_loader_close(loader, &err);
7062
7063 purple_imgstore_unref(custom_img); 7077 purple_imgstore_unref(custom_img);
7064 7078
7065 anim = gdk_pixbuf_loader_get_animation(loader); 7079 if (!gtkconv->u.im->anim) {
7066 if (anim) 7080 purple_debug_error("gtkconv", "Couldn't load icon for conv %s\n",
7067 g_object_ref(G_OBJECT(anim)); 7081 purple_conversation_get_name(conv));
7068 g_object_unref(loader);
7069
7070 if (!anim)
7071 return; 7082 return;
7072 gtkconv->u.im->anim = anim;
7073
7074 if (err) {
7075 purple_debug(PURPLE_DEBUG_ERROR, "gtkconv",
7076 "Buddy icon error: %s\n", err->message);
7077 g_error_free(err);
7078 } 7083 }
7079 7084
7080 if (gdk_pixbuf_animation_is_static_image(gtkconv->u.im->anim)) { 7085 if (gdk_pixbuf_animation_is_static_image(gtkconv->u.im->anim)) {
7081 GdkPixbuf *stat; 7086 GdkPixbuf *stat;
7082 gtkconv->u.im->iter = NULL; 7087 gtkconv->u.im->iter = NULL;