about summary refs log tree commit diff
path: root/sysdeps/posix/raise.c
blob: f171dc2407ca313f07b8d7ce1edf02460a3f01dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <internal-signals.h>

/* Raise the signal SIG.  POSIX requires raise to be async-signal-safe,
   but calling getpid and then raise is *not* async-signal-safe; if an
   async signal handler calls fork (which is also async-signal-safe)
   in between the two operations, and returns normally on both sides
   of the fork, kill will be called twice.  So we must block signals
   around the operation.  See bug 15368 for more detail.
 */
int
__libc_raise (int sig)
{
  /* Disallow sending the signals we use for cancellation, timers,
     setxid, etc.  This check is also performed in __kill, but
     if we do it now we can avoid blocking and then unblocking signals
     unnecessarily.  */
  if (__glibc_unlikely (__is_internal_signal (sig)))
    {
      __set_errno (EINVAL);
      return -1;
    }

  /* We can safely assume that __libc_signal_block_app and
     __libc_signal_restore_set will not fail, because
     sigprocmask can only fail under three circumstances:

     1. sigsetsize != sizeof (sigset_t) (EINVAL)
     2. a failure in copy from/to user space (EFAULT)
     3. an invalid 'how' operation (EINVAL)

     Getting any of these would indicate a bug in either the
     definition of sigset_t or the implementations of the
     wrappers.  */
  sigset_t omask;
  __libc_signal_block_app (&omask);

  int ret = __kill (__getpid (), sig);

  /* ... But just because sigprocmask will not fail here, that doesn't
     mean it won't clobber errno.  */
  int save_errno = errno;
  __libc_signal_restore_set (&omask);
  __set_errno (errno);

  return ret;
}
strong_alias (__libc_raise, raise)
libc_hidden_def (raise)
weak_alias (raise, gsignal)