GCC Code Coverage Report


Directory: ./
File: common/src/error.c
Date: 2026-11-08 20:01:15
Exec Total Coverage
Lines: 22 64 34.4%
Functions: 1 4 25.0%
Branches: 8 24 33.3%

Line Branch Exec Source
1 /*
2 * Common code for error reporting.
3 * Copyright © 2009-2026, albinoloverats ~ Software Development
4 * email: webmaster@albinoloverats.net
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <errno.h>
22 #include <signal.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdarg.h>
28
29 #if !defined _WIN32 && !defined __CYGWIN__ && !defined __FreeBSD__
30 #include <execinfo.h>
31 #endif
32
33 #include <stdint.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <stdbool.h>
37
38 #include "error.h"
39 #include "non-gnu.h"
40
41 #define ERROR_DIVIDE "\n********** ********** ********** **********\n\n"
42 #define ERROR_DIVIDE_LEN 46
43 #define ERROR_CURSOR "\e[?25h\n"
44 #define ERROR_CURSOR_LEN 7
45
46 #ifdef BUILD_GUI
47 static void error_gui_alert(const char * const restrict);
48
49 static GtkWidget *error_gui_window;
50 static GtkWidget *error_gui_message;
51 #endif
52
53 extern void on_error(int) __attribute__((noreturn));
54
55 static char *int_to_ascii(int);
56
57 static volatile sig_atomic_t error_inited = 0;
58
59 static volatile sig_atomic_t fatal_error_in_progress = 0;
60
61 ✗ extern void on_error(int s)
62 {
63 ✗ if (fatal_error_in_progress)
64 ✗ raise(s);
65 ✗ fatal_error_in_progress = 1;
66
67 ✗ write(STDERR_FILENO, ERROR_CURSOR, ERROR_CURSOR_LEN);
68 ✗ write(STDERR_FILENO, ERROR_DIVIDE, ERROR_DIVIDE_LEN);
69
70 ✗ char m[32] = { 0x0 };
71 ✗ strcat(m, "Received fatal signal [");
72 ✗ strcat(m, int_to_ascii(s));
73 ✗ strcat(m, "]");
74 ✗ psignal(s, m);
75
76 #ifdef BUILD_GUI
77 error_gui_alert(m);
78 #endif
79
80 #if !defined _WIN32 && !defined __CYGWIN__ && !defined __FreeBSD__
81 void *bt[BACKTRACE_BUFFER_LIMIT];
82 ✗ int c = backtrace(bt, BACKTRACE_BUFFER_LIMIT);
83 ✗ char **sym = backtrace_symbols(bt, c);
84 ✗ if (sym)
85 ✗ for (int i = 0; i < c; i++)
86 {
87 ✗ write(STDERR_FILENO, sym[i], strlen(sym[i]));
88 ✗ write(STDERR_FILENO, "\n", 1);
89 }
90 #endif
91
92 ✗ write(STDERR_FILENO, ERROR_DIVIDE, ERROR_DIVIDE_LEN);
93
94 #ifndef __APPLE__
95 ✗ signal(s, SIG_DFL);
96 ✗ raise(s);
97 ✗ __builtin_unreachable();
98 #else
99 exit(errno);
100 #endif
101 }
102
103 ✗ extern void error_init(void)
104 {
105 ✗ if (error_inited)
106 ✗ return;
107
108 ✗ signal(SIGILL, on_error);
109 ✗ signal(SIGSEGV, on_error);
110 ✗ signal(SIGBUS, on_error);
111 ✗ signal(SIGABRT, on_error);
112 ✗ signal(SIGSYS, on_error);
113 //signal(SIGPROF, on_error);
114
115 ✗ error_inited = 1;
116
117 ✗ return;
118 }
119
120 9 extern void die(const char * const restrict s, ...)
121 {
122 9 int ex = errno;
123 9 char *d = NULL;
124 va_list ap;
125 9 va_start(ap, s);
126 #ifndef _WIN32
127 9 vasprintf(&d, s, ap);
128 #else
129 uint8_t l = 0xFF;
130 if ((d = calloc(l, sizeof l)))
131 vsnprintf(d, l - 1, s, ap);
132 #endif
133 9 fprintf(stderr, "%s", d);
134 9 va_end(ap);
135 9 fprintf(stderr, "\n");
136 #ifdef BUILD_GUI
137 error_gui_alert(d);
138 #endif
139 9 free(d);
140
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 if (ex)
141 {
142 8 char * const restrict e = strdup(strerror(ex));
143
3/4
✓ Branch 0 taken 178 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 170 times.
✓ Branch 3 taken 8 times.
178 for (uint32_t i = 0; e && i < strlen(e); i++)
144 170 e[i] = tolower((unsigned char)e[i]);
145 8 fprintf(stderr, "%s\n", e);
146 8 free(e);
147 #if !defined _WIN32 && !defined __CYGWIN__ && !defined __FreeBSD__
148 void *bt[BACKTRACE_BUFFER_LIMIT];
149 8 int c = backtrace(bt, BACKTRACE_BUFFER_LIMIT);
150 8 char **sym = backtrace_symbols(bt, c);
151
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (sym)
152 {
153
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 8 times.
79 for (int i = 0; i < c; i++)
154 71 fprintf(stderr, "%s\n", sym[i]);
155 8 free(sym);
156 }
157 #endif
158 }
159 9 exit(ex);
160 }
161
162 #ifdef BUILD_GUI
163 extern void error_gui_init(GtkWidget *w, GtkWidget *m)
164 {
165 error_init();
166 error_gui_window = w;
167 error_gui_message = m;
168 }
169
170 G_MODULE_EXPORT gboolean error_gui_close(void *w, void *d)
171 {
172 (void)w;
173 (void)d;
174 gtk_widget_hide(error_gui_window);
175 return TRUE;
176 }
177
178 static void error_gui_alert(const char * const restrict msg)
179 {
180 if (error_gui_window)
181 {
182 gtk_label_set_text((GtkLabel *)error_gui_message, msg);
183 gtk_dialog_run((GtkDialog *)error_gui_window);
184 }
185 return;
186 }
187 #endif
188
189 #define INT_DIGITS 19 /* enough for 64 bit integer */
190
191 ✗ static char *int_to_ascii(int i)
192 {
193 /* Room for INT_DIGITS digits, - and '\0' */
194 static char buf[INT_DIGITS + 2];
195 ✗ char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */
196 ✗ if (i >= 0)
197 do
198 {
199 ✗ *--p = '0' + (i % 10);
200 ✗ i /= 10;
201 }
202 ✗ while (i != 0);
203 else
204 { /* i < 0 */
205 do
206 {
207 ✗ *--p = '0' - (i % 10);
208 ✗ i /= 10;
209 }
210 ✗ while (i != 0);
211 ✗ *--p = '-';
212 }
213 ✗ return p;
214 }
215