Skip to content

Commit ff9c317

Browse files
Merge branch 'main' into capi-PySys_GetAttr3
2 parents e76228a + 3d40317 commit ff9c317

File tree

95 files changed

+2015
-1776
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2015
-1776
lines changed

Doc/c-api/exceptions.rst

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -921,11 +921,7 @@ because the :ref:`call protocol <call>` takes care of recursion handling.
921921
922922
Marks a point where a recursive C-level call is about to be performed.
923923
924-
If :c:macro:`!USE_STACKCHECK` is defined, this function checks if the OS
925-
stack overflowed using :c:func:`PyOS_CheckStack`. If this is the case, it
926-
sets a :exc:`MemoryError` and returns a nonzero value.
927-
928-
The function then checks if the recursion limit is reached. If this is the
924+
The function then checks if the stack limit is reached. If this is the
929925
case, a :exc:`RecursionError` is set and a nonzero value is returned.
930926
Otherwise, zero is returned.
931927

Doc/c-api/module.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ The available slot types are:
415415
in one module definition.
416416
417417
If ``Py_mod_multiple_interpreters`` is not specified, the import
418-
machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED``.
418+
machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``.
419419
420420
.. versionadded:: 3.12
421421

Doc/c-api/unicode.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,15 @@ APIs:
607607
decref'ing the returned objects.
608608
609609
610+
.. c:function:: const char* PyUnicode_GetDefaultEncoding(void)
611+
612+
Return the name of the default string encoding, ``"utf-8"``.
613+
See :func:`sys.getdefaultencoding`.
614+
615+
The returned string does not need to be freed, and is valid
616+
until interpreter shutdown.
617+
618+
610619
.. c:function:: Py_ssize_t PyUnicode_GetLength(PyObject *unicode)
611620
612621
Return the length of the Unicode object, in code points.

Doc/data/refcounts.dat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2770,6 +2770,9 @@ PyUnicode_FromFormatV:PyObject*::+1:
27702770
PyUnicode_FromFormatV:const char*:format::
27712771
PyUnicode_FromFormatV:va_list:args::
27722772

2773+
PyUnicode_GetDefaultEncoding:const char*:::
2774+
PyUnicode_GetDefaultEncoding::void::
2775+
27732776
PyUnicode_GetLength:Py_ssize_t:::
27742777
PyUnicode_GetLength:PyObject*:unicode:0:
27752778

Doc/library/sys.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -771,8 +771,8 @@ always available. Unless explicitly noted otherwise, all variables are read-only
771771

772772
.. function:: getdefaultencoding()
773773

774-
Return the name of the current default string encoding used by the Unicode
775-
implementation.
774+
Return ``'utf-8'``. This is the name of the default string encoding, used
775+
in methods like :meth:`str.encode`.
776776

777777

778778
.. function:: getdlopenflags()

Doc/library/wsgiref.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ in type annotations.
119119
applications to set up dummy environments. It should NOT be used by actual WSGI
120120
servers or applications, since the data is fake!
121121

122-
Example usage::
122+
Example usage (see also :func:`~wsgiref.simple_server.demo_app`
123+
for another example)::
123124

124125
from wsgiref.util import setup_testing_defaults
125126
from wsgiref.simple_server import make_server
@@ -312,6 +313,8 @@ request. (E.g., using the :func:`shift_path_info` function from
312313
as :mod:`wsgiref.simple_server`) is able to run a simple WSGI application
313314
correctly.
314315

316+
The *start_response* callable should follow the :class:`.StartResponse` protocol.
317+
315318

316319
.. class:: WSGIServer(server_address, RequestHandlerClass)
317320

@@ -679,7 +682,9 @@ input, output, and error streams.
679682

680683
This method can access the current error using ``sys.exception()``,
681684
and should pass that information to *start_response* when calling it (as
682-
described in the "Error Handling" section of :pep:`3333`).
685+
described in the "Error Handling" section of :pep:`3333`). In particular,
686+
the *start_response* callable should follow the :class:`.StartResponse`
687+
protocol.
683688

684689
The default implementation just uses the :attr:`error_status`,
685690
:attr:`error_headers`, and :attr:`error_body` attributes to generate an output
@@ -781,7 +786,7 @@ in :pep:`3333`.
781786
.. versionadded:: 3.11
782787

783788

784-
.. class:: StartResponse()
789+
.. class:: StartResponse
785790

786791
A :class:`typing.Protocol` describing :pep:`start_response()
787792
<3333#the-start-response-callable>`
@@ -816,7 +821,8 @@ in :pep:`3333`.
816821
Examples
817822
--------
818823

819-
This is a working "Hello World" WSGI application::
824+
This is a working "Hello World" WSGI application, where the *start_response*
825+
callable should follow the :class:`.StartResponse` protocol::
820826

821827
"""
822828
Every WSGI application must have an application object - a callable

Include/cpython/object.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -487,18 +487,19 @@ PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate);
487487
* we have headroom above the trigger limit */
488488
#define Py_TRASHCAN_HEADROOM 50
489489

490+
/* Helper function for Py_TRASHCAN_BEGIN */
491+
PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count);
492+
490493
#define Py_TRASHCAN_BEGIN(op, dealloc) \
491494
do { \
492495
PyThreadState *tstate = PyThreadState_Get(); \
493-
if (tstate->c_recursion_remaining <= Py_TRASHCAN_HEADROOM && Py_TYPE(op)->tp_dealloc == (destructor)dealloc) { \
496+
if (_Py_ReachedRecursionLimitWithMargin(tstate, 1) && Py_TYPE(op)->tp_dealloc == (destructor)dealloc) { \
494497
_PyTrash_thread_deposit_object(tstate, (PyObject *)op); \
495498
break; \
496-
} \
497-
tstate->c_recursion_remaining--;
499+
}
498500
/* The body of the deallocator is here. */
499501
#define Py_TRASHCAN_END \
500-
tstate->c_recursion_remaining++; \
501-
if (tstate->delete_later && tstate->c_recursion_remaining > (Py_TRASHCAN_HEADROOM*2)) { \
502+
if (tstate->delete_later && !_Py_ReachedRecursionLimitWithMargin(tstate, 2)) { \
502503
_PyTrash_thread_destroy_chain(tstate); \
503504
} \
504505
} while (0);

Include/cpython/pystate.h

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ struct _ts {
112112
int py_recursion_remaining;
113113
int py_recursion_limit;
114114

115-
int c_recursion_remaining;
115+
int c_recursion_remaining; /* Retained for backwards compatibility. Do not use */
116116
int recursion_headroom; /* Allow 50 more calls to handle any errors. */
117117

118118
/* 'tracing' keeps track of the execution depth when tracing/profiling.
@@ -202,36 +202,7 @@ struct _ts {
202202
PyObject *threading_local_sentinel;
203203
};
204204

205-
#ifdef Py_DEBUG
206-
// A debug build is likely built with low optimization level which implies
207-
// higher stack memory usage than a release build: use a lower limit.
208-
# define Py_C_RECURSION_LIMIT 500
209-
#elif defined(__s390x__)
210-
# define Py_C_RECURSION_LIMIT 800
211-
#elif defined(_WIN32) && defined(_M_ARM64)
212-
# define Py_C_RECURSION_LIMIT 1000
213-
#elif defined(_WIN32)
214-
# define Py_C_RECURSION_LIMIT 3000
215-
#elif defined(__ANDROID__)
216-
// On an ARM64 emulator, API level 34 was OK with 10000, but API level 21
217-
// crashed in test_compiler_recursion_limit.
218-
# define Py_C_RECURSION_LIMIT 3000
219-
#elif defined(_Py_ADDRESS_SANITIZER)
220-
# define Py_C_RECURSION_LIMIT 4000
221-
#elif defined(__sparc__)
222-
// test_descr crashed on sparc64 with >7000 but let's keep a margin of error.
223-
# define Py_C_RECURSION_LIMIT 4000
224-
#elif defined(__wasi__)
225-
// Based on wasmtime 16.
226-
# define Py_C_RECURSION_LIMIT 5000
227-
#elif defined(__hppa__) || defined(__powerpc64__)
228-
// test_descr crashed with >8000 but let's keep a margin of error.
229-
# define Py_C_RECURSION_LIMIT 5000
230-
#else
231-
// This value is duplicated in Lib/test/support/__init__.py
232-
# define Py_C_RECURSION_LIMIT 10000
233-
#endif
234-
205+
# define Py_C_RECURSION_LIMIT 5000
235206

236207
/* other API */
237208

@@ -246,7 +217,6 @@ _PyThreadState_UncheckedGet(void)
246217
return PyThreadState_GetUnchecked();
247218
}
248219

249-
250220
// Disable tracing and profiling.
251221
PyAPI_FUNC(void) PyThreadState_EnterTracing(PyThreadState *tstate);
252222

Include/internal/pycore_ceval.h

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -193,18 +193,28 @@ extern void _PyEval_DeactivateOpCache(void);
193193

194194
/* --- _Py_EnterRecursiveCall() ----------------------------------------- */
195195

196-
#ifdef USE_STACKCHECK
197-
/* With USE_STACKCHECK macro defined, trigger stack checks in
198-
_Py_CheckRecursiveCall() on every 64th call to _Py_EnterRecursiveCall. */
199-
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
200-
return (tstate->c_recursion_remaining-- < 0
201-
|| (tstate->c_recursion_remaining & 63) == 0);
196+
#if !_Py__has_builtin(__builtin_frame_address)
197+
static uintptr_t return_pointer_as_int(char* p) {
198+
return (uintptr_t)p;
202199
}
200+
#endif
201+
202+
static inline uintptr_t
203+
_Py_get_machine_stack_pointer(void) {
204+
#if _Py__has_builtin(__builtin_frame_address)
205+
return (uintptr_t)__builtin_frame_address(0);
203206
#else
204-
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
205-
return tstate->c_recursion_remaining-- < 0;
206-
}
207+
char here;
208+
/* Avoid compiler warning about returning stack address */
209+
return return_pointer_as_int(&here);
207210
#endif
211+
}
212+
213+
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
214+
uintptr_t here_addr = _Py_get_machine_stack_pointer();
215+
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
216+
return here_addr < _tstate->c_stack_soft_limit;
217+
}
208218

209219
// Export for '_json' shared extension, used via _Py_EnterRecursiveCall()
210220
// static inline function.
@@ -220,23 +230,30 @@ static inline int _Py_EnterRecursiveCallTstate(PyThreadState *tstate,
220230
return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where));
221231
}
222232

223-
static inline void _Py_EnterRecursiveCallTstateUnchecked(PyThreadState *tstate) {
224-
assert(tstate->c_recursion_remaining > 0);
225-
tstate->c_recursion_remaining--;
226-
}
227-
228233
static inline int _Py_EnterRecursiveCall(const char *where) {
229234
PyThreadState *tstate = _PyThreadState_GET();
230235
return _Py_EnterRecursiveCallTstate(tstate, where);
231236
}
232237

233-
static inline void _Py_LeaveRecursiveCallTstate(PyThreadState *tstate) {
234-
tstate->c_recursion_remaining++;
238+
static inline void _Py_LeaveRecursiveCallTstate(PyThreadState *tstate) {
239+
(void)tstate;
240+
}
241+
242+
PyAPI_FUNC(void) _Py_InitializeRecursionLimits(PyThreadState *tstate);
243+
244+
static inline int _Py_ReachedRecursionLimit(PyThreadState *tstate) {
245+
uintptr_t here_addr = _Py_get_machine_stack_pointer();
246+
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
247+
if (here_addr > _tstate->c_stack_soft_limit) {
248+
return 0;
249+
}
250+
if (_tstate->c_stack_hard_limit == 0) {
251+
_Py_InitializeRecursionLimits(tstate);
252+
}
253+
return here_addr <= _tstate->c_stack_soft_limit;
235254
}
236255

237256
static inline void _Py_LeaveRecursiveCall(void) {
238-
PyThreadState *tstate = _PyThreadState_GET();
239-
_Py_LeaveRecursiveCallTstate(tstate);
240257
}
241258

242259
extern struct _PyInterpreterFrame* _PyEval_GetFrame(void);
@@ -327,7 +344,6 @@ void _Py_unset_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit);
327344

328345
PyAPI_FUNC(PyObject *) _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value);
329346

330-
331347
#ifdef __cplusplus
332348
}
333349
#endif

Include/internal/pycore_symtable.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ struct symtable {
8282
PyObject *st_private; /* name of current class or NULL */
8383
_PyFutureFeatures *st_future; /* module's future features that affect
8484
the symbol table */
85-
int recursion_depth; /* current recursion depth */
86-
int recursion_limit; /* recursion limit */
8785
};
8886

8987
typedef struct _symtable_entry {

0 commit comments

Comments
 (0)