Nuitka
The Python compiler
Loading...
Searching...
No Matches
HelpersRaising.c
1// Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3/* This helpers is used to work with lists.
4
5*/
6
7// This file is included from another C file, help IDEs to still parse it on
8// its own.
9#ifdef __IDE_ONLY__
10#include "nuitka/prelude.h"
11#endif
12
13static void FORMAT_TYPE_ERROR1(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state,
14 char const *format, char const *arg) {
15 PyObject *exception_value = Nuitka_String_FromFormat(format, arg);
16 CHECK_OBJECT(exception_value);
17
18 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_VALUE1(tstate, exception_state, PyExc_TypeError, exception_value);
19}
20
21static void FORMAT_TYPE_ERROR2(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state,
22 char const *format, char const *arg1, char const *arg2) {
23 PyObject *exception_value = Nuitka_String_FromFormat(format, arg1, arg2);
24 CHECK_OBJECT(exception_value);
25
26 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_VALUE1(tstate, exception_state, PyExc_TypeError, exception_value);
27}
28
29#if PYTHON_VERSION < 0x266
30#define WRONG_EXCEPTION_TYPE_ERROR_MESSAGE "exceptions must be classes or instances, not %s"
31#elif PYTHON_VERSION < 0x300
32#define WRONG_EXCEPTION_TYPE_ERROR_MESSAGE "exceptions must be old-style classes or derived from BaseException, not %s"
33#else
34#define WRONG_EXCEPTION_TYPE_ERROR_MESSAGE "exceptions must derive from BaseException"
35#endif
36
37// Next, replace a tuple in exception type creation with its first item
38#if PYTHON_VERSION < 0x3c0
39static void UNPACK_TUPLE_EXCEPTION_TYPE(struct Nuitka_ExceptionPreservationItem *exception_state) {
40 while (unlikely(PyTuple_Check(exception_state->exception_type)) &&
41 PyTuple_GET_SIZE(exception_state->exception_type) > 0) {
42 PyObject *tmp = exception_state->exception_type;
43 exception_state->exception_type = PyTuple_GET_ITEM(exception_state->exception_type, 0);
44 Py_INCREF(exception_state->exception_type);
45 Py_DECREF(tmp);
46 }
47}
48#endif
49
50#if PYTHON_VERSION < 0x3c0
51void RAISE_EXCEPTION_WITH_TYPE(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state) {
52 exception_state->exception_value = NULL;
53 exception_state->exception_tb = NULL;
54
55#if PYTHON_VERSION < 0x300
56 // Next, repeatedly, replace a tuple exception with its first item
57 UNPACK_TUPLE_EXCEPTION_TYPE(exception_state);
58#endif
59
60 if (PyExceptionClass_Check(exception_state->exception_type)) {
61 NORMALIZE_EXCEPTION(tstate, &exception_state->exception_type, &exception_state->exception_value,
62 &exception_state->exception_tb);
63
64#if PYTHON_VERSION >= 0x300
65 CHAIN_EXCEPTION(tstate, exception_state->exception_value);
66#endif
67 return;
68 } else if (PyExceptionInstance_Check(exception_state->exception_type)) {
69 exception_state->exception_value = exception_state->exception_type;
70 exception_state->exception_type = PyExceptionInstance_Class(exception_state->exception_type);
71 Py_INCREF(exception_state->exception_type);
72
73#if PYTHON_VERSION >= 0x300
74 CHAIN_EXCEPTION(tstate, exception_state->exception_value);
75
76 // Note: Cannot be assigned here.
77 assert(exception_state->exception_tb == NULL);
78 exception_state->exception_tb = GET_EXCEPTION_TRACEBACK(exception_state->exception_value);
79 Py_XINCREF(exception_state->exception_tb);
80#endif
81
82 return;
83 } else {
84 PyObject *old_exception_type = exception_state->exception_type;
85
86 FORMAT_TYPE_ERROR1(tstate, exception_state, WRONG_EXCEPTION_TYPE_ERROR_MESSAGE,
87 Py_TYPE(exception_state->exception_type)->tp_name);
88
89 Py_DECREF(old_exception_type);
90
91 return;
92 }
93}
94
95void RAISE_EXCEPTION_WITH_TYPE_AND_VALUE(PyThreadState *tstate,
96 struct Nuitka_ExceptionPreservationItem *exception_state) {
97 CHECK_EXCEPTION_STATE(exception_state);
98
99 exception_state->exception_tb = NULL;
100
101 // Non-empty tuple exceptions are the first element.
102 UNPACK_TUPLE_EXCEPTION_TYPE(exception_state);
103
104 if (PyExceptionClass_Check(exception_state->exception_type)) {
105 NORMALIZE_EXCEPTION_STATE(tstate, exception_state);
106#if PYTHON_VERSION >= 0x270
107 if (unlikely(!PyExceptionInstance_Check(exception_state->exception_value))) {
108 char const *exception_type_type = Py_TYPE(exception_state->exception_type)->tp_name;
109 char const *exception_value_type = Py_TYPE(exception_state->exception_value)->tp_name;
110
111 RELEASE_ERROR_OCCURRED_STATE(exception_state);
112
113 FORMAT_TYPE_ERROR2(tstate, exception_state,
114 "calling %s() should have returned an instance of BaseException, not '%s'",
115 exception_type_type, exception_value_type);
116 }
117#endif
118
119 return;
120 } else if (PyExceptionInstance_Check(exception_state->exception_type)) {
121 if (unlikely(exception_state->exception_value != NULL && exception_state->exception_value != Py_None)) {
122 RELEASE_ERROR_OCCURRED_STATE(exception_state);
123 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_STR(tstate, exception_state, PyExc_TypeError,
124 "instance exception may not have a separate value");
125
126 return;
127 }
128
129 // The type is rather a value, so we are overriding it here.
130 exception_state->exception_value = exception_state->exception_type;
131 exception_state->exception_type = PyExceptionInstance_Class(exception_state->exception_type);
132 Py_INCREF(exception_state->exception_type);
133
134 return;
135 } else {
136 char const *exception_type_type = Py_TYPE(exception_state->exception_type)->tp_name;
137
138 RELEASE_ERROR_OCCURRED_STATE(exception_state);
139
140 FORMAT_TYPE_ERROR1(tstate, exception_state, WRONG_EXCEPTION_TYPE_ERROR_MESSAGE, exception_type_type);
141
142 return;
143 }
144}
145
146#else
147
148void RAISE_EXCEPTION_WITH_VALUE(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state) {
149 ASSERT_NORMALIZED_EXCEPTION_VALUE(exception_state->exception_value);
150
151 CHAIN_EXCEPTION(tstate, exception_state->exception_value);
152}
153#endif
154
155#if PYTHON_VERSION >= 0x300
156void RAISE_EXCEPTION_WITH_CAUSE(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state,
157 PyObject *exception_cause) {
158 CHECK_EXCEPTION_STATE(exception_state);
159 CHECK_OBJECT(exception_cause);
160
161#if PYTHON_VERSION < 0x3c0
162 exception_state->exception_tb = NULL;
163#endif
164
165 // None is not a cause.
166 if (exception_cause == Py_None) {
167 Py_DECREF_IMMORTAL(exception_cause);
168 exception_cause = NULL;
169 } else if (PyExceptionClass_Check(exception_cause)) {
170 PyObject *old_exception_cause = exception_cause;
171 exception_cause = CALL_FUNCTION_NO_ARGS(tstate, exception_cause);
172 Py_DECREF(old_exception_cause);
173
174 if (unlikely(exception_cause == NULL)) {
175 RELEASE_ERROR_OCCURRED_STATE(exception_state);
176 FETCH_ERROR_OCCURRED_STATE(tstate, exception_state);
177
178 return;
179 }
180 }
181
182 if (unlikely(exception_cause != NULL && !PyExceptionInstance_Check(exception_cause))) {
183 RELEASE_ERROR_OCCURRED_STATE(exception_state);
184
185#ifdef _NUITKA_FULL_COMPAT
186 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_STR(tstate, exception_state, PyExc_TypeError,
187 "exception causes must derive from BaseException");
188#else
189 FORMAT_TYPE_ERROR1(tstate, exception_state, "exception causes must derive from BaseException (%s does not)",
190 Py_TYPE(exception_cause)->tp_name);
191#endif
192
193 return;
194 }
195
196#if PYTHON_VERSION < 0x3c0
197 if (PyExceptionClass_Check(exception_state->exception_type)) {
198 char const *exception_type_type = Py_TYPE(exception_state->exception_type)->tp_name;
199
200 NORMALIZE_EXCEPTION_STATE(tstate, exception_state);
201
202 if (unlikely(!PyExceptionInstance_Check(exception_state->exception_value))) {
203 Py_XDECREF(exception_cause);
204
205 char const *exception_value_type = Py_TYPE(exception_state->exception_value)->tp_name;
206
207 RELEASE_ERROR_OCCURRED_STATE(exception_state);
208
209 FORMAT_TYPE_ERROR2(tstate, exception_state,
210 "calling %s() should have returned an instance of BaseException, not '%s'",
211 exception_type_type, exception_value_type);
212
213 return;
214 }
215
216 Nuitka_Exception_SetCause(exception_state->exception_value, exception_cause);
217 CHAIN_EXCEPTION(tstate, exception_state->exception_value);
218 } else if (PyExceptionInstance_Check(exception_state->exception_type)) {
219 exception_state->exception_value = exception_state->exception_type;
220 exception_state->exception_type = PyExceptionInstance_Class(exception_state->exception_type);
221 Py_INCREF(exception_state->exception_type);
222
223 Nuitka_Exception_SetCause(exception_state->exception_value, exception_cause);
224 CHAIN_EXCEPTION(tstate, exception_state->exception_value);
225 } else {
226 Py_XDECREF(exception_cause);
227
228 char const *exception_type_type = Py_TYPE(exception_state->exception_type)->tp_name;
229
230 RELEASE_ERROR_OCCURRED_STATE(exception_state);
231
232 FORMAT_TYPE_ERROR1(tstate, exception_state, WRONG_EXCEPTION_TYPE_ERROR_MESSAGE, exception_type_type);
233 }
234#else
235 ASSERT_NORMALIZED_EXCEPTION_VALUE(exception_state->exception_value);
236
237 Nuitka_Exception_SetCause(exception_state->exception_value, exception_cause);
238 CHAIN_EXCEPTION(tstate, exception_state->exception_value);
239#endif
240}
241#endif
242
243#if PYTHON_VERSION < 0x300
244void RAISE_EXCEPTION_WITH_TRACEBACK(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state) {
245 if (exception_state->exception_tb == (PyTracebackObject *)Py_None) {
246 Py_DECREF_IMMORTAL(exception_state->exception_tb);
247 exception_state->exception_tb = NULL;
248 }
249
250 // Non-empty tuple exceptions are the first element.
251 UNPACK_TUPLE_EXCEPTION_TYPE(exception_state);
252
253 if (PyExceptionClass_Check(exception_state->exception_type)) {
254 NORMALIZE_EXCEPTION_STATE(tstate, exception_state);
255#if PYTHON_VERSION >= 0x270
256 if (unlikely(!PyExceptionInstance_Check(exception_state->exception_value))) {
257 char const *exception_type_type = Py_TYPE(exception_state->exception_type)->tp_name;
258 char const *exception_value_type = Py_TYPE(exception_state->exception_value)->tp_name;
259
260 RELEASE_ERROR_OCCURRED_STATE(exception_state);
261
262 // TODO: It would be even more safe to create the format value
263 // before releasing the value.
264 FORMAT_TYPE_ERROR2(tstate, exception_state,
265 "calling %s() should have returned an instance of BaseException, not '%s'",
266 exception_type_type, exception_value_type);
267 }
268#endif
269
270 return;
271 } else if (PyExceptionInstance_Check(exception_state->exception_type)) {
272 if (unlikely(exception_state->exception_value != NULL && exception_state->exception_value != Py_None)) {
273 RELEASE_ERROR_OCCURRED_STATE(exception_state);
274 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_STR(tstate, exception_state, PyExc_TypeError,
275 "instance exception may not have a separate value");
276
277 return;
278 }
279
280 // The type is rather a value, so we are overriding it here.
281 exception_state->exception_value = exception_state->exception_type;
282 exception_state->exception_type = PyExceptionInstance_Class(exception_state->exception_type);
283 Py_INCREF(exception_state->exception_type);
284
285 return;
286 } else {
287 FORMAT_TYPE_ERROR1(tstate, exception_state, WRONG_EXCEPTION_TYPE_ERROR_MESSAGE,
288 Py_TYPE(exception_state->exception_type)->tp_name);
289
290 return;
291 }
292}
293#endif
294
295bool RERAISE_EXCEPTION(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state) {
296#if PYTHON_VERSION < 0x3b0
297 exception_state->exception_type = EXC_TYPE(tstate) != NULL ? EXC_TYPE(tstate) : Py_None;
298 Py_INCREF(exception_state->exception_type);
299 exception_state->exception_value = EXC_VALUE(tstate);
300 Py_XINCREF(exception_state->exception_value);
301 exception_state->exception_tb = (PyTracebackObject *)EXC_TRACEBACK(tstate);
302 Py_XINCREF(exception_state->exception_tb);
303
304 if (unlikely(exception_state->exception_type == Py_None)) {
305#if PYTHON_VERSION >= 0x300
306 RELEASE_ERROR_OCCURRED_STATE(exception_state);
307
308 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_STR(tstate, exception_state, PyExc_RuntimeError,
309 "No active exception to reraise");
310#else
311 char const *exception_type_type = Py_TYPE(exception_state->exception_type)->tp_name;
312
313 RELEASE_ERROR_OCCURRED_STATE(exception_state);
314
315 FORMAT_TYPE_ERROR1(tstate, exception_state, WRONG_EXCEPTION_TYPE_ERROR_MESSAGE, exception_type_type);
316
317#endif
318
319 return false;
320 }
321#else
322 exception_state->exception_value = EXC_VALUE(tstate);
323
324 if (exception_state->exception_value == Py_None || exception_state->exception_value == NULL) {
325 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_STR(tstate, exception_state, PyExc_RuntimeError,
326 "No active exception to reraise");
327
328 return false;
329 } else {
330 Py_INCREF(exception_state->exception_value);
331
332#if PYTHON_VERSION < 0x3c0
333 exception_state->exception_type = PyExceptionInstance_Class(exception_state->exception_value);
334 Py_INCREF(exception_state->exception_type);
335 exception_state->exception_tb = GET_EXCEPTION_TRACEBACK(exception_state->exception_value);
336 Py_XINCREF(exception_state->exception_tb);
337#endif
338 }
339#endif
340
341 // Check for value to be present as well.
342 CHECK_EXCEPTION_STATE(exception_state);
343 CHECK_OBJECT(exception_state->exception_value);
344
345 return true;
346}
347
348// Raise NameError for a given variable name.
349void RAISE_CURRENT_EXCEPTION_NAME_ERROR(PyThreadState *tstate, struct Nuitka_ExceptionPreservationItem *exception_state,
350 PyObject *variable_name) {
351#if PYTHON_VERSION < 0x300
352 PyObject *exception_value_str =
353 Nuitka_String_FromFormat("name '%s' is not defined", Nuitka_String_AsString_Unchecked(variable_name));
354#else
355 PyObject *exception_value_str = Nuitka_String_FromFormat("name '%U' is not defined", variable_name);
356#endif
357
358 PyObject *exception_value = MAKE_EXCEPTION_FROM_TYPE_ARG0(tstate, PyExc_NameError, exception_value_str);
359 Py_DECREF(exception_value_str);
360
361#if PYTHON_VERSION >= 0x300
362 CHAIN_EXCEPTION(tstate, exception_value);
363#endif
364
365 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_VALUE1_NORMALIZED(tstate, exception_state, PyExc_NameError,
366 exception_value);
367}
368
369#if PYTHON_VERSION < 0x300
370void RAISE_CURRENT_EXCEPTION_GLOBAL_NAME_ERROR(PyThreadState *tstate,
371 struct Nuitka_ExceptionPreservationItem *exception_state,
372 PyObject *variable_name) {
373 PyObject *exception_value_str =
374 Nuitka_String_FromFormat("global name '%s' is not defined", Nuitka_String_AsString_Unchecked(variable_name));
375 PyObject *exception_value = MAKE_EXCEPTION_FROM_TYPE_ARG0(tstate, PyExc_NameError, exception_value_str);
376 Py_DECREF(exception_value_str);
377
378 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_VALUE1_NORMALIZED(tstate, exception_state, PyExc_NameError,
379 exception_value);
380}
381#endif
382
383PyObject *NORMALIZE_EXCEPTION_VALUE_FOR_RAISE(PyThreadState *tstate, PyObject *exception_type) {
384 // Allow setting the value to NULL for time savings with quick type only errors
385 CHECK_OBJECT(exception_type);
386
387 if (PyExceptionInstance_Check(exception_type)) {
388 return Py_NewRef(exception_type);
389 } else {
390 if (unlikely(!PyExceptionClass_Check(exception_type))) {
391 struct Nuitka_ExceptionPreservationItem exception_state;
392 FORMAT_TYPE_ERROR1(tstate, &exception_state, WRONG_EXCEPTION_TYPE_ERROR_MESSAGE,
393 Py_TYPE(exception_type)->tp_name);
394 RESTORE_ERROR_OCCURRED_STATE(tstate, &exception_state);
395 return NULL;
396 }
397
398 PyObject *exception_value = CALL_FUNCTION_NO_ARGS(tstate, exception_type);
399
400 if (unlikely(exception_value == NULL)) {
401 return NULL;
402 }
403
404 if (unlikely(!PyExceptionInstance_Check(exception_value))) {
405 struct Nuitka_ExceptionPreservationItem exception_state;
406 FORMAT_TYPE_ERROR2(tstate, &exception_state,
407 "calling %R should have returned an instance of BaseException, not %R",
408 (char const *)exception_type, (char const *)Py_TYPE(exception_value));
409 RESTORE_ERROR_OCCURRED_STATE(tstate, &exception_state);
410
411 Py_DECREF(exception_value);
412 return NULL;
413 }
414
415 return exception_value;
416 }
417}
418
419#if PYTHON_VERSION >= 0x300
420PyObject *MAKE_STOP_ITERATION_EMPTY(void) {
421 // Fake tstate object is OK, no tuple will be needed.
422 return Nuitka_CreateStopIteration(NULL, NULL);
423}
424
425PyObject *MAKE_BASE_EXCEPTION_DERIVED_EMPTY(PyObject *exception_type) {
426 // Note: Fake tstate object is OK, no tuple will be needed to store anything
427 // in args.
428 PyBaseExceptionObject *result = Nuitka_BaseExceptionSingleArg_new(NULL, (PyTypeObject *)exception_type, NULL);
429
430 return (PyObject *)result;
431}
432
433#endif
434// Part of "Nuitka", an optimizing Python compiler that is compatible and
435// integrates with CPython, but also works on its own.
436//
437// Licensed under the Apache License, Version 2.0 (the "License");
438// you may not use this file except in compliance with the License.
439// You may obtain a copy of the License at
440//
441// http://www.apache.org/licenses/LICENSE-2.0
442//
443// Unless required by applicable law or agreed to in writing, software
444// distributed under the License is distributed on an "AS IS" BASIS,
445// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
446// See the License for the specific language governing permissions and
447// limitations under the License.
Definition exceptions.h:712