Coverage Report

Created: 2026-04-12 07:03

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