GNOME Bugzilla – Bug 391907
Glib::Error::throw_exception() doesn't return Glib::Error instance in --disable-api-exceptions mode
Last modified: 2007-01-06 19:53:56 UTC
Steps to reproduce: 1. Compile this program with debugging info #include <gdkmm/pixbuf.h> #include <gtkmm/main.h> #include <glib/gmessages.h> int main (int argc, char* argv[]) { Gtk::Main loop (argc, argv); GError* gerror = 0; Glib::RefPtr<Gdk::Pixbuf> pb = Glib::wrap (gdk_pixbuf_new_from_file ("/tmp/nosuch", &gerror)); if (gerror) { printf ("%s:%d: Error: %s\n", __FILE__, __LINE__, gerror->message); std::auto_ptr<Glib::Error> e (::Glib::Error::throw_exception (gerror)); // Never reached g_assert_not_reached (); } else { printf ("%s:%d: No error\n", __FILE__, __LINE__); } return 1; } 2. Break on main.cc:19 3. Observe nonsensical output: main.cc:15: Error: Failed to open file '/tmp/nosuch': No such file or directory main.cc:23: No error Stack trace: There isn't a stack trace at the point of failure; the program just jumps into the wrong logic paths and crashes later because error-throwing operations appear to have succeeded. Other information: This code is basically lifted from the sources to Gdk::Pixbuf::create_from_file(), for the purposes of instrumenting it with debugging output. Apologies for using the Pixbuf C++ binding type from gtkmm as a demonstration of the bug. I didn't find any operations which ought to provoke the same Glib::FileError instance in the core glibmm API itself. At any rate, I don't think that the Gdk::Pixbuf code is at issue here; I can witness the Glib::FileError::throw_func() call return and produce the expected instance of Glib::FileError. The strangeness begins when Glib::Error::throw_exception() attempts to return that auto_ptr to the calling code (here, main.cc:16.
It turns out that this is behavior is caused by a (mis)optimization that GCC performs due to the stray "__noreturn__" annotation on Glib::Error::throw_exception(), in error.h: #ifdef GLIBMM_EXCEPTIONS_ENABLED static void throw_exception(GError* gobject) G_GNUC_NORETURN; #else static std::auto_ptr<Glib::Error> throw_exception(GError* gobject) G_GNUC_NORETURN; #endif //GLIBMM_EXCEPTIONS_ENABLED It is mistakenly assumed that control never returns to the sites which call this function with !GLIBMM_EXCEPTIONS_ENABLED, so the "jump" instructions which prevent the "then" clause from falling down into the "else" clause, are just omitted. This was already fixed in the 2.10.9 release, so I guess all that's left is for me to point out that the issue is more serious than the ChangeLog entry which said that removing the annotation avoided some compiler warnings. :)
OK, I'm closing this bug since it is already fixed. By the way, it's not a "(mis)optimization" of GCC but most definitely an error in glibmm. The fact that you hit this bug shows that the optimization is working :) Note that the noreturn attribute makes GCC optimize at the caller site, so it really can't just ignore the attribute if the function does return, since it doesn't know the definition. But there's definitely a warning when compiling the function itself; I wonder why noone has seen that earlier.