]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/unwind.c
Disable spurious -Wstringop-overflow for setjmp/longjmp (bug 26647)
[thirdparty/glibc.git] / nptl / unwind.c
CommitLineData
d614a753 1/* Copyright (C) 2003-2020 Free Software Foundation, Inc.
09d65ff3
UD
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>
4 and Richard Henderson <rth@redhat.com>, 2003.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
59ba27a6 17 License along with the GNU C Library; if not, see
5a82c748 18 <https://www.gnu.org/licenses/>. */
09d65ff3
UD
19
20#include <setjmp.h>
7f0dfae0 21#include <stdio.h>
09d65ff3 22#include <stdlib.h>
d347a4ab 23#include <string.h>
6e66dc78 24#include <unistd.h>
09d65ff3 25#include "pthreadP.h"
2098d403 26#include <libc-diag.h>
8dea90aa 27#include <jmpbuf-unwind.h>
09d65ff3 28
44e94149 29#ifdef _STACK_GROWS_DOWN
675620f7
UD
30# define FRAME_LEFT(frame, other, adj) \
31 ((uintptr_t) frame - adj >= (uintptr_t) other - adj)
44e94149 32#elif _STACK_GROWS_UP
675620f7
UD
33# define FRAME_LEFT(frame, other, adj) \
34 ((uintptr_t) frame - adj <= (uintptr_t) other - adj)
44e94149
UD
35#else
36# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
37#endif
38
09d65ff3
UD
39static _Unwind_Reason_Code
40unwind_stop (int version, _Unwind_Action actions,
41 _Unwind_Exception_Class exc_class,
42 struct _Unwind_Exception *exc_obj,
43 struct _Unwind_Context *context, void *stop_parameter)
44{
45 struct pthread_unwind_buf *buf = stop_parameter;
44e94149
UD
46 struct pthread *self = THREAD_SELF;
47 struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
48 int do_longjump = 0;
f76c8499 49
675620f7
UD
50 /* Adjust all pointers used in comparisons, so that top of thread's
51 stack is at the top of address space. Without that, things break
52 if stack is allocated above the main stack. */
53 uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size;
09d65ff3
UD
54
55 /* Do longjmp if we're at "end of stack", aka "end of unwind data".
56 We assume there are only C frame without unwind data in between
57 here and the jmp_buf target. Otherwise simply note that the CFA
58 of a function is NOT within it's stack frame; it's the SP of the
59 previous frame. */
60 if ((actions & _UA_END_OF_STACK)
675620f7
UD
61 || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context,
62 adj))
44e94149
UD
63 do_longjump = 1;
64
a1ffb40e 65 if (__glibc_unlikely (curp != NULL))
44e94149
UD
66 {
67 /* Handle the compatibility stuff. Execute all handlers
68 registered with the old method which would be unwound by this
69 step. */
70 struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup;
ca7b8af5 71 void *cfa = (void *) (_Unwind_Ptr) _Unwind_GetCFA (context);
44e94149 72
675620f7 73 if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj)))
44e94149
UD
74 {
75 do
76 {
77 /* Pointer to the next element. */
78 struct _pthread_cleanup_buffer *nextp = curp->__prev;
79
80 /* Call the handler. */
81 curp->__routine (curp->__arg);
82
83 /* To the next. */
84 curp = nextp;
85 }
675620f7
UD
86 while (curp != oldp
87 && (do_longjump || FRAME_LEFT (cfa, curp, adj)));
44e94149
UD
88
89 /* Mark the current element as handled. */
90 THREAD_SETMEM (self, cleanup, curp);
91 }
92 }
93
2098d403
JM
94 DIAG_PUSH_NEEDS_COMMENT;
95#if __GNUC_PREREQ (7, 0)
96 /* This call results in a -Wstringop-overflow warning because struct
97 pthread_unwind_buf is smaller than jmp_buf. setjmp and longjmp
98 do not use anything beyond the common prefix (they never access
99 the saved signal mask), so that is a false positive. */
100 DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overflow=");
101#endif
44e94149 102 if (do_longjump)
f76c8499 103 __libc_unwind_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1);
2098d403 104 DIAG_POP_NEEDS_COMMENT;
09d65ff3
UD
105
106 return _URC_NO_REASON;
107}
108
109
110static void
111unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc)
112{
29b095a1
UD
113 /* When we get here a C++ catch block didn't rethrow the object. We
114 cannot handle this case and therefore abort. */
7f0dfae0 115 __libc_fatal ("FATAL: exception not rethrown\n");
09d65ff3
UD
116}
117
09d65ff3
UD
118
119void
120__cleanup_fct_attribute __attribute ((noreturn))
121__pthread_unwind (__pthread_unwind_buf_t *buf)
122{
123 struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
124 struct pthread *self = THREAD_SELF;
125
44e94149
UD
126 /* This is not a catchable exception, so don't provide any details about
127 the exception type. We do need to initialize the field though. */
128 THREAD_SETMEM (self, exc.exception_class, 0);
c515fb51 129 THREAD_SETMEM (self, exc.exception_cleanup, &unwind_cleanup);
44e94149
UD
130
131 _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf);
09d65ff3
UD
132 /* NOTREACHED */
133
134 /* We better do not get here. */
135 abort ();
136}
56421b23 137hidden_def (__pthread_unwind)
09d65ff3
UD
138
139
140void
141__cleanup_fct_attribute __attribute ((noreturn))
142__pthread_unwind_next (__pthread_unwind_buf_t *buf)
143{
144 struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
145
49b65043 146 __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev);
09d65ff3 147}
da0c02ee 148hidden_def (__pthread_unwind_next)