Coverage Report

Created: 2026-02-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/utils/signal_posix.c
Line
Count
Source
1
#include <pthread.h>
2
#include <stddef.h>
3
#include <errno.h>
4
#include <signal.h>
5
#include <termios.h>
6
7
#include <winpr/wlog.h>
8
#include <winpr/debug.h>
9
10
#include <freerdp/log.h>
11
#include <freerdp/utils/signal.h>
12
13
#include "platform_signal.h"
14
15
0
#define TAG FREERDP_TAG("utils.signal.posix")
16
17
static pthread_mutex_t signal_handler_lock = PTHREAD_MUTEX_INITIALIZER;
18
19
void fsig_lock(void)
20
0
{
21
0
  const int rc = pthread_mutex_lock(&signal_handler_lock);
22
0
  if (rc != 0)
23
0
  {
24
0
    char ebuffer[256] = WINPR_C_ARRAY_INIT;
25
0
    WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
26
0
             winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
27
0
  }
28
0
}
29
30
void fsig_unlock(void)
31
0
{
32
0
  const int rc = pthread_mutex_unlock(&signal_handler_lock);
33
0
  if (rc != 0)
34
0
  {
35
0
    char ebuffer[256] = WINPR_C_ARRAY_INIT;
36
0
    WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
37
0
             winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
38
0
  }
39
0
}
40
41
static void fatal_handler(int signum)
42
0
{
43
0
  struct sigaction default_sigaction;
44
0
  sigset_t this_mask;
45
0
  static BOOL recursive = FALSE;
46
47
0
  if (!recursive)
48
0
  {
49
0
    recursive = TRUE;
50
    // NOLINTNEXTLINE(concurrency-mt-unsafe)
51
0
    WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
52
53
0
    winpr_log_backtrace(TAG, WLOG_ERROR, 20);
54
0
  }
55
56
0
  default_sigaction.sa_handler = SIG_DFL;
57
0
  sigfillset(&(default_sigaction.sa_mask));
58
0
  default_sigaction.sa_flags = 0;
59
0
  sigaction(signum, &default_sigaction, NULL);
60
0
  sigemptyset(&this_mask);
61
0
  sigaddset(&this_mask, signum);
62
0
  pthread_sigmask(SIG_UNBLOCK, &this_mask, NULL);
63
0
  (void)raise(signum);
64
0
}
65
66
static const int term_signals[] = { SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM };
67
68
static const int fatal_signals[] = { SIGABRT,   SIGALRM, SIGBUS,  SIGFPE,  SIGHUP,
69
                                   SIGILL,    SIGSEGV, SIGTTIN, SIGTTOU,
70
#ifdef SIGPOLL
71
                                   SIGPOLL,
72
#endif
73
#ifdef SIGPROF
74
                                   SIGPROF,
75
#endif
76
#ifdef SIGSYS
77
                                   SIGSYS,
78
#endif
79
                                   SIGTRAP,
80
#ifdef SIGVTALRM
81
                                   SIGVTALRM,
82
#endif
83
                                   SIGXCPU,   SIGXFSZ };
84
85
static BOOL register_handlers(const int* signals, size_t count, void (*handler)(int))
86
0
{
87
0
  WINPR_ASSERT(signals || (count == 0));
88
0
  WINPR_ASSERT(handler);
89
90
0
  sigset_t orig_set = WINPR_C_ARRAY_INIT;
91
0
  struct sigaction saction = WINPR_C_ARRAY_INIT;
92
93
0
  pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
94
95
0
  sigfillset(&(saction.sa_mask));
96
0
  sigdelset(&(saction.sa_mask), SIGCONT);
97
98
0
  saction.sa_handler = handler;
99
0
  saction.sa_flags = 0;
100
101
0
  for (size_t x = 0; x < count; x++)
102
0
  {
103
0
    struct sigaction orig_sigaction = WINPR_C_ARRAY_INIT;
104
0
    if (sigaction(signals[x], NULL, &orig_sigaction) == 0)
105
0
    {
106
0
      if (orig_sigaction.sa_handler != SIG_IGN)
107
0
      {
108
0
        sigaction(signals[x], &saction, NULL);
109
0
      }
110
0
    }
111
0
  }
112
113
0
  pthread_sigmask(SIG_SETMASK, &orig_set, NULL);
114
115
0
  return TRUE;
116
0
}
117
118
static void unregister_handlers(const int* signals, size_t count)
119
0
{
120
0
  WINPR_ASSERT(signals || (count == 0));
121
122
0
  sigset_t orig_set = WINPR_C_ARRAY_INIT;
123
0
  struct sigaction saction = WINPR_C_ARRAY_INIT;
124
125
0
  pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
126
127
0
  sigfillset(&(saction.sa_mask));
128
0
  sigdelset(&(saction.sa_mask), SIGCONT);
129
130
0
  saction.sa_handler = SIG_IGN;
131
0
  saction.sa_flags = 0;
132
133
0
  for (size_t x = 0; x < count; x++)
134
0
  {
135
0
    sigaction(signals[x], &saction, NULL);
136
0
  }
137
138
0
  pthread_sigmask(SIG_SETMASK, &orig_set, NULL);
139
0
}
140
141
static void unregister_all_handlers(void)
142
0
{
143
0
  unregister_handlers(fatal_signals, ARRAYSIZE(fatal_signals));
144
0
  unregister_handlers(term_signals, ARRAYSIZE(term_signals));
145
0
}
146
147
int freerdp_handle_signals(void)
148
0
{
149
0
  int rc = -1;
150
151
0
  fsig_lock();
152
153
0
  WLog_DBG(TAG, "Registering signal hook...");
154
155
0
  (void)atexit(unregister_all_handlers);
156
0
  if (!register_handlers(fatal_signals, ARRAYSIZE(fatal_signals), fatal_handler))
157
0
    goto fail;
158
0
  if (!register_handlers(term_signals, ARRAYSIZE(term_signals), fsig_term_handler))
159
0
    goto fail;
160
161
  /* Ignore SIGPIPE signal. */
162
0
  (void)signal(SIGPIPE, SIG_IGN);
163
0
  fsig_handlers_registered = TRUE;
164
0
  rc = 0;
165
0
fail:
166
0
  fsig_unlock();
167
0
  return rc;
168
0
}