#include <clutter-gtk/clutter-gtk.h>
#endif
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
gboolean thumb_format_changed = FALSE;
static RemoteConnection *remote_connection = NULL;
gchar *desktop_file_template;
gchar *instance_identifier;
+#if defined(SA_SIGINFO)
+void sig_handler_cb(int signo, siginfo_t *info, void *UNUSED(context))
+{
+ gchar hex_char[16];
+ const gchar *signal_name = NULL;
+ gint i = 0;
+ guint64 addr;
+ guint64 char_index;
+ ssize_t len;
+#ifdef HAVE_EXECINFO_H
+ gint bt_size;
+ void *bt[1024];
+#endif
+ struct signals
+ {
+ gint sig_no;
+ const gchar *sig_name;
+ };
+ struct signals signals_list[7];
+
+ signals_list[0].sig_no = SIGABRT;
+ signals_list[0].sig_name = "Abort";
+ signals_list[1].sig_no = SIGBUS;
+ signals_list[1].sig_name = "Bus error";
+ signals_list[2].sig_no = SIGFPE;
+ signals_list[2].sig_name = "Floating-point exception";
+ signals_list[3].sig_no = SIGILL;
+ signals_list[3].sig_name = "Illegal instruction";
+ signals_list[4].sig_no = SIGIOT;
+ signals_list[4].sig_name = "IOT trap";
+ signals_list[5].sig_no = SIGSEGV;
+ signals_list[5].sig_name = "Invalid memory reference";
+ signals_list[6].sig_no = -1;
+ signals_list[6].sig_name = "END";
+
+ hex_char[0] = '0';
+ hex_char[1] = '1';
+ hex_char[2] = '2';
+ hex_char[3] = '3';
+ hex_char[4] = '4';
+ hex_char[5] = '5';
+ hex_char[6] = '6';
+ hex_char[7] = '7';
+ hex_char[8] = '8';
+ hex_char[9] = '9';
+ hex_char[10] = 'a';
+ hex_char[11] = 'b';
+ hex_char[12] = 'c';
+ hex_char[13] = 'd';
+ hex_char[14] = 'e';
+ hex_char[15] = 'f';
+
+ signal_name = "Unknown signal";
+ while (signals_list[i].sig_no != -1)
+ {
+ if (signo == signals_list[i].sig_no)
+ {
+ signal_name = signals_list[i].sig_name;
+ break;
+ }
+ i++;
+ }
+
+ len = write(STDERR_FILENO, "Geeqie fatal error\n", 19);
+ len = write(STDERR_FILENO, "Signal: ", 8);
+ len = write(STDERR_FILENO, signal_name, strlen(signal_name));
+ len = write(STDERR_FILENO, "\n", 1);
+
+ len = write(STDERR_FILENO, "Code: ", 6);
+ len = write(STDERR_FILENO, (info->si_code == SEGV_MAPERR) ? "Address not mapped" : "Invalid permissions", strlen((info->si_code == SEGV_MAPERR) ? "Address not mapped" : "Invalid permissions"));
+ len = write(STDERR_FILENO, "\n", 1);
+
+ len = write(STDERR_FILENO, "Address: ", 9);
+
+ if (info->si_addr == 0)
+ {
+ len = write(STDERR_FILENO, "0x0\n", 4);
+ }
+ else
+ {
+ /* Assume the address is 64-bit */
+ len = write(STDERR_FILENO, "0x", 2);
+ addr = reinterpret_cast<guint64>(info->si_addr);
+
+ for (i = 0; i < 16; i++)
+ {
+ char_index = addr & 0xf000000000000000;
+ char_index = char_index >> 60;
+ addr = addr << 4;
+
+ len = write(STDERR_FILENO, &hex_char[char_index], 1);
+ }
+ len = write(STDERR_FILENO, "\n", 1);
+ }
+
+#ifdef HAVE_EXECINFO_H
+ bt_size = backtrace(bt, 1024);
+ backtrace_symbols_fd(bt, bt_size, STDERR_FILENO);
+#endif
+
+ exit(EXIT_FAILURE);
+}
+#else /* defined(SA_SIGINFO) */
+void sig_handler_cb(int UNUSED(signo))
+{
+#ifdef HAVE_EXECINFO_H
+ gint bt_size;
+ void *bt[1024];
+#endif
+
+ write(STDERR_FILENO, "Geeqie fatal error\n", 19);
+ write(STDERR_FILENO, "Signal: Segmentation fault\n", 27);
+
+#ifdef HAVE_EXECINFO_H
+ bt_size = backtrace(bt, 1024);
+ backtrace_symbols_fd(bt, bt_size, STDERR_FILENO);
+#endif
+
+ exit(EXIT_FAILURE);
+}
+#endif /* defined(SA_SIGINFO) */
+
/*
*-----------------------------------------------------------------------------
* keyboard functions
work = files;
while (work)
{
- FileData *fd = work->data;
+ FileData *fd = static_cast<FileData *>(work->data);
if (!*path) *path = remove_level_from_path(fd->path);
if (!*file) *file = g_strdup(fd->path);
*list = g_list_prepend(*list, fd);
{
command_line->tools_show = TRUE;
- remote_list = g_list_append(remote_list, "+t");
+ remote_list = g_list_append(remote_list, g_strdup("+t"));
}
else if (strcmp(cmd_line, "-t") == 0 ||
strcmp(cmd_line, "--without-tools") == 0)
{
command_line->tools_hide = TRUE;
- remote_list = g_list_append(remote_list, "-t");
+ remote_list = g_list_append(remote_list, g_strdup("-t"));
}
else if (strcmp(cmd_line, "-f") == 0 ||
strcmp(cmd_line, "--fullscreen") == 0)
geometry = g_strdup_printf("--geometry=%s", command_line->geometry);
remote_list = g_list_prepend(remote_list, geometry);
}
- remote_list = g_list_prepend(remote_list, "--new-window");
+ remote_list = g_list_prepend(remote_list, g_strdup("--new-window"));
}
g_free(app_lock);
}
while (work)
{
- gchar *opt = work->data;
+ gchar *opt = static_cast<gchar *>(work->data);
command_line_errors = g_string_append(command_line_errors, opt);
command_line_errors = g_string_append(command_line_errors, "\n");
gboolean changed)
{
GString *gstring = g_string_new(changed ? NULL : "; ");
- SecureSaveInfo *ssi = data;
+ SecureSaveInfo *ssi = static_cast<SecureSaveInfo *>(data);
gchar *tmp, *name;
g_string_append(gstring, "(gtk_accel_path \"");
list = layout_window_list;
while (list)
{
- tmp_lw = list->data;
+ tmp_lw = static_cast<LayoutWindow *>(list->data);
if (!g_str_has_prefix(tmp_lw->options.id, "lw"))
{
- save_layout(list->data);
+ save_layout(static_cast<_LayoutWindow *>(list->data));
}
list = list->next;
}
exit_program_final();
}
-/* This code is supposed to handle situation when a file mmaped by image_loader
+/* This code attempts to handle situation when a file mmaped by image_loader
* or by exif loader is truncated by some other process.
- * This is probably not completely correct according to posix, because
- * mmap is not in the list of calls that can be used safely in signal handler,
- * but anyway, the handler is called in situation when the application would
- * crash otherwise.
- * Ideas for improvement are welcome ;)
+ * This code is incorrect according to POSIX, because:
+ *
+ * mmap is not async-signal-safe and thus may not be called from a signal handler
+ *
+ * mmap must be called with a valid file descriptor. POSIX requires that
+ * a fildes argument of -1 must cause mmap to return EBADF.
+ *
+ * See https://github.com/BestImageViewer/geeqie/issues/1052 for discussion of
+ * an alternative approach.
*/
/** @FIXME this probably needs some better ifdefs. Please report any compilation problems */
#if defined(SIGBUS) && defined(SA_SIGINFO)
static void sigbus_handler_cb(int UNUSED(signum), siginfo_t *info, void *UNUSED(context))
{
- unsigned long pagesize = sysconf(_SC_PAGE_SIZE);
- DEBUG_1("SIGBUS %p", info->si_addr);
- mmap((void *)(((unsigned long)info->si_addr / pagesize) * pagesize), pagesize, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ /*
+ * @FIXME Design and implement a POSIX-acceptable approach,
+ * after first documenting the sitations where SIGBUS occurs.
+ * See https://github.com/BestImageViewer/geeqie/issues/1052 for discussion
+ */
+
+ DEBUG_1("SIGBUS %p NOT HANDLED", info->si_addr);
+ exit(EXIT_FAILURE);
}
#endif
-static void setup_sigbus_handler(void)
-{
-#if defined(SIGBUS) && defined(SA_SIGINFO)
- struct sigaction sigbus_action;
- sigfillset(&sigbus_action.sa_mask);
- sigbus_action.sa_sigaction = sigbus_handler_cb;
- sigbus_action.sa_flags = SA_SIGINFO;
+//static void setup_sigbus_handler(void)
+//{
+//#if defined(SIGBUS) && defined(SA_SIGINFO)
+ //struct sigaction sigbus_action;
+ //sigfillset(&sigbus_action.sa_mask);
+ //sigbus_action.sa_sigaction = sigbus_handler_cb;
+ //sigbus_action.sa_flags = SA_SIGINFO;
- sigaction(SIGBUS, &sigbus_action, NULL);
-#endif
+ //sigaction(SIGBUS, &sigbus_action, NULL);
+//#endif
+//}
+
+static void setup_sig_handler(void)
+{
+ struct sigaction sigsegv_action;
+ sigfillset(&sigsegv_action.sa_mask);
+ sigsegv_action.sa_sigaction = sig_handler_cb;
+ sigsegv_action.sa_flags = SA_SIGINFO;
+
+ sigaction(SIGABRT, &sigsegv_action, NULL);
+ sigaction(SIGBUS, &sigsegv_action, NULL);
+ sigaction(SIGFPE, &sigsegv_action, NULL);
+ sigaction(SIGILL, &sigsegv_action, NULL);
+ sigaction(SIGIOT, &sigsegv_action, NULL);
+ sigaction(SIGSEGV, &sigsegv_action, NULL);
}
static void set_theme_bg_color()
if (!options->image.use_custom_border_color)
{
work = layout_window_list;
- lw = work->data;
+ lw = static_cast<LayoutWindow *>(work->data);
style_context = gtk_widget_get_style_context(lw->window);
gtk_style_context_get_background_color(style_context, GTK_STATE_FLAG_NORMAL, &bg_color);
while (work)
{
- lw = work->data;
+ lw = static_cast<LayoutWindow *>(work->data);
image_background_set_color(lw->image, &theme_color);
work = work->next;
}
g_free(path);
}
-gboolean stderr_channel_cb(GIOChannel *source, GIOCondition UNUSED(condition), gpointer UNUSED(data))
-{
- static GString *message_str = NULL;
- gchar buf[10] = {0};
- gsize count;
-
- if (!message_str)
- {
- message_str = g_string_new(NULL);
- }
-
- g_io_channel_read_chars(source, buf, 1, &count, NULL);
-
- if (count > 0)
- {
- if (buf[0] == '\n')
- {
- log_printf("%s", message_str->str);
- g_string_free(message_str, TRUE);
- message_str = NULL;
- }
- else
- {
- message_str = g_string_append_c(message_str, buf[0]);
- }
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
gint main(gint argc, gchar *argv[])
{
CollectionData *first_collection = NULL;
gboolean single_dir = TRUE;
LayoutWindow *lw;
GtkSettings *default_settings;
- gint fd_stderr[2];
- GIOChannel *stderr_channel;
gdk_set_allowed_backends("x11,*");
gdk_threads_init();
gdk_threads_enter();
+ /* seg. fault handler */
+#ifdef HAVE_DEVELOPER
+ backward::SignalHandling sh{};
+#else
+ setup_sig_handler();
+#endif
+
/* init execution time counter (debug only) */
init_exec_time();
textdomain(PACKAGE);
#endif
- /* Tee stderr to log window */
- if (pipe(fd_stderr) == 0)
- {
- if (dup2(fd_stderr[1], fileno(stderr)) != -1)
- {
- close(fd_stderr[1]);
- stderr_channel = g_io_channel_unix_new(fd_stderr[0]);
- g_io_add_watch(stderr_channel, G_IO_IN, (GIOFunc)stderr_channel_cb, NULL);
- }
- }
-
exif_init();
#ifdef HAVE_LUA
/* setup random seed for random slideshow */
srand(time(NULL));
+#if 0
+ /* See later comment; this handler leads to UB. */
setup_sigbus_handler();
+#endif
/* register global notify functions */
file_data_register_notify_func(cache_notify_cb, NULL, NOTIFY_PRIORITY_HIGH);
}
DEBUG_1("%s main: pixbuf_inline_register_stock_icons", get_exec_time());
+ gtk_icon_theme_add_resource_path(gtk_icon_theme_get_default(), GQ_RESOURCE_PATH_ICONS);
pixbuf_inline_register_stock_icons();
DEBUG_1("%s main: setting default options before commandline handling", get_exec_time());
CollectWindow *cw;
const gchar *path;
- path = work->data;
+ path = static_cast<const gchar *>(work->data);
work = work->next;
cw = collection_window_new(path);
{
gchar *dirname;
- dirname = g_path_get_dirname(work->data);
+ dirname = g_path_get_dirname(static_cast<const gchar *>(work->data));
if (!path)
{
path = g_strdup(dirname);
{
FileData *fd;
- fd = file_data_new_simple(work->data);
+ fd = file_data_new_simple(static_cast<const gchar *>(work->data));
collection_add(cd, fd, FALSE);
file_data_unref(fd);
work = work->next;
work = work->next;
}
- if (cd->list) layout_image_set_collection(NULL, cd, cd->list->data);
+ if (cd->list) layout_image_set_collection(NULL, cd, static_cast<CollectInfo *>(cd->list->data));
/* mem leak, we never unref this collection when !startup_command_line_collection
* (the image view of the main window does not hold a ref to the collection)
set_theme_bg_color();
}
+ /* Show a fade-out notification window if the server has a newer AppImage version */
+ if (options->appimage_notifications && g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
+ {
+ appimage_notification();
+ }
+
DEBUG_1("%s main: gtk_main", get_exec_time());
gtk_main();