Skip to content

Commit 7f1e440

Browse files
authored
Merge branch 'main' into gh-121045
2 parents 89fa135 + a9bb3c7 commit 7f1e440

Some content is hidden

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

41 files changed

+587
-966
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ jobs:
307307
with:
308308
save: false
309309
- name: Configure CPython
310-
run: ./configure --config-cache --with-pydebug --with-openssl=$OPENSSL_DIR
310+
run: ./configure --config-cache --enable-slower-safety --with-pydebug --with-openssl=$OPENSSL_DIR
311311
- name: Build CPython
312312
run: make -j4
313313
- name: Display build info
@@ -380,6 +380,7 @@ jobs:
380380
../cpython-ro-srcdir/configure \
381381
--config-cache \
382382
--with-pydebug \
383+
--enable-slower-safety \
383384
--with-openssl=$OPENSSL_DIR
384385
- name: Build CPython out-of-tree
385386
working-directory: ${{ env.CPYTHON_BUILDDIR }}

.github/workflows/reusable-macos.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ jobs:
5353
./configure \
5454
--config-cache \
5555
--with-pydebug \
56+
--enable-slower-safety \
5657
${{ inputs.free-threading && '--disable-gil' || '' }} \
5758
--prefix=/opt/python-dev \
5859
--with-openssl="$(brew --prefix [email protected])"

.github/workflows/reusable-tsan.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ jobs:
3636
# Install clang-18
3737
wget https://apt.llvm.org/llvm.sh
3838
chmod +x llvm.sh
39-
sudo ./llvm.sh 17 # gh-121946: llvm-18 package is temporarily broken
40-
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-17 100
41-
sudo update-alternatives --set clang /usr/bin/clang-17
42-
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-17 100
43-
sudo update-alternatives --set clang++ /usr/bin/clang++-17
39+
sudo ./llvm.sh 18
40+
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100
41+
sudo update-alternatives --set clang /usr/bin/clang-18
42+
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100
43+
sudo update-alternatives --set clang++ /usr/bin/clang++-18
4444
# Reduce ASLR to avoid TSAN crashing
4545
sudo sysctl -w vm.mmap_rnd_bits=28
4646
- name: TSAN Option Setup

.github/workflows/reusable-ubuntu.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ jobs:
6969
../cpython-ro-srcdir/configure
7070
--config-cache
7171
--with-pydebug
72+
--enable-slower-safety
7273
--with-openssl=$OPENSSL_DIR
7374
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
7475
- name: Build CPython out-of-tree

Doc/using/configure.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,25 @@ Security Options
907907
The settings ``python`` and *STRING* also set TLS 1.2 as minimum
908908
protocol version.
909909

910+
.. option:: --disable-safety
911+
912+
Disable compiler options that are recommended by `OpenSSF`_ for security reasons with no performance overhead.
913+
If this option is not enabled, CPython will be built based on safety compiler options with no slow down.
914+
915+
.. _OpenSSF: https://openssf.org/
916+
917+
.. versionadded:: 3.14
918+
919+
.. option:: --enable-slower-safety
920+
921+
Enable compiler options that are recommended by `OpenSSF`_ for security reasons which require overhead.
922+
If this option is not enabled, CPython will not be built based on safety compiler options which performance impact.
923+
924+
.. _OpenSSF: https://openssf.org/
925+
926+
.. versionadded:: 3.14
927+
928+
910929
macOS Options
911930
-------------
912931

Doc/whatsnew/3.14.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ New Features
7575
Other Language Changes
7676
======================
7777

78+
* Incorrect usage of :keyword:`await` and asynchronous comprehensions
79+
is now detected even if the code is optimized away by the :option:`-O`
80+
command line option. For example, ``python -O -c 'assert await 1'``
81+
now produces a :exc:`SyntaxError`. (Contributed by Jelle Zijlstra in :gh:`121637`.)
82+
7883
* Added class methods :meth:`float.from_number` and :meth:`complex.from_number`
7984
to convert a number to :class:`float` or :class:`complex` type correspondingly.
8085
They raise an error if the argument is a string.

Include/internal/pycore_context.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# error "this header requires Py_BUILD_CORE define"
66
#endif
77

8-
#include "pycore_freelist.h" // _PyFreeListState
98
#include "pycore_hamt.h" // PyHamtObject
109

1110

Include/internal/pycore_dict.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
#include "pycore_freelist.h" // _PyFreeListState
1211
#include "pycore_object.h" // PyManagedDictPointer
1312
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_ACQUIRE
1413

Include/internal/pycore_floatobject.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
#include "pycore_freelist.h" // _PyFreeListState
1211
#include "pycore_unicodeobject.h" // _PyUnicodeWriter
1312

1413
/* runtime lifecycle */

Include/internal/pycore_freelist.h

Lines changed: 92 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -8,144 +8,109 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
// PyTuple_MAXSAVESIZE - largest tuple to save on free list
12-
// PyTuple_MAXFREELIST - maximum number of tuples of each size to save
13-
14-
#ifdef WITH_FREELISTS
15-
// with freelists
16-
# define PyTuple_MAXSAVESIZE 20
17-
# define PyTuple_NFREELISTS PyTuple_MAXSAVESIZE
18-
# define PyTuple_MAXFREELIST 2000
19-
# define PyList_MAXFREELIST 80
20-
# define PyDict_MAXFREELIST 80
21-
# define PyFloat_MAXFREELIST 100
22-
# define PyContext_MAXFREELIST 255
23-
# define _PyAsyncGen_MAXFREELIST 80
24-
# define _PyObjectStackChunk_MAXFREELIST 4
25-
#else
26-
# define PyTuple_NFREELISTS 0
27-
# define PyTuple_MAXFREELIST 0
28-
# define PyList_MAXFREELIST 0
29-
# define PyDict_MAXFREELIST 0
30-
# define PyFloat_MAXFREELIST 0
31-
# define PyContext_MAXFREELIST 0
32-
# define _PyAsyncGen_MAXFREELIST 0
33-
# define _PyObjectStackChunk_MAXFREELIST 0
34-
#endif
35-
36-
struct _Py_list_freelist {
37-
#ifdef WITH_FREELISTS
38-
PyListObject *items[PyList_MAXFREELIST];
39-
int numfree;
11+
#include "pycore_freelist_state.h" // struct _Py_freelists
12+
#include "pycore_object.h" // _PyObject_IS_GC
13+
#include "pycore_pystate.h" // _PyThreadState_GET
14+
#include "pycore_code.h" // OBJECT_STAT_INC
15+
16+
static inline struct _Py_freelists *
17+
_Py_freelists_GET(void)
18+
{
19+
PyThreadState *tstate = _PyThreadState_GET();
20+
#ifdef Py_DEBUG
21+
_Py_EnsureTstateNotNULL(tstate);
4022
#endif
41-
};
42-
43-
struct _Py_tuple_freelist {
44-
#if WITH_FREELISTS
45-
/* There is one freelist for each size from 1 to PyTuple_MAXSAVESIZE.
46-
The empty tuple is handled separately.
4723

48-
Each tuple stored in the array is the head of the linked list
49-
(and the next available tuple) for that size. The actual tuple
50-
object is used as the linked list node, with its first item
51-
(ob_item[0]) pointing to the next node (i.e. the previous head).
52-
Each linked list is initially NULL. */
53-
PyTupleObject *items[PyTuple_NFREELISTS];
54-
int numfree[PyTuple_NFREELISTS];
24+
#ifdef Py_GIL_DISABLED
25+
return &((_PyThreadStateImpl*)tstate)->freelists;
5526
#else
56-
char _unused; // Empty structs are not allowed.
57-
#endif
58-
};
59-
60-
struct _Py_float_freelist {
61-
#ifdef WITH_FREELISTS
62-
/* Special free list
63-
free_list is a singly-linked list of available PyFloatObjects,
64-
linked via abuse of their ob_type members. */
65-
int numfree;
66-
PyFloatObject *items;
67-
#endif
68-
};
69-
70-
struct _Py_dict_freelist {
71-
#ifdef WITH_FREELISTS
72-
/* Dictionary reuse scheme to save calls to malloc and free */
73-
PyDictObject *items[PyDict_MAXFREELIST];
74-
int numfree;
27+
return &tstate->interp->object_state.freelists;
7528
#endif
76-
};
29+
}
7730

78-
struct _Py_dictkeys_freelist {
79-
#ifdef WITH_FREELISTS
80-
/* Dictionary keys reuse scheme to save calls to malloc and free */
81-
PyDictKeysObject *items[PyDict_MAXFREELIST];
82-
int numfree;
83-
#endif
84-
};
31+
#ifndef WITH_FREELISTS
32+
#define _Py_FREELIST_FREE(NAME, op, freefunc) freefunc(op)
33+
#define _Py_FREELIST_PUSH(NAME, op, limit) (0)
34+
#define _Py_FREELIST_POP(TYPE, NAME) (NULL)
35+
#define _Py_FREELIST_POP_MEM(NAME) (NULL)
36+
#define _Py_FREELIST_SIZE(NAME) (0)
37+
#else
38+
// Pushes `op` to the freelist, calls `freefunc` if the freelist is full
39+
#define _Py_FREELIST_FREE(NAME, op, freefunc) \
40+
_PyFreeList_Free(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), \
41+
Py_ ## NAME ## _MAXFREELIST, freefunc)
42+
// Pushes `op` to the freelist, returns 1 if successful, 0 if the freelist is full
43+
#define _Py_FREELIST_PUSH(NAME, op, limit) \
44+
_PyFreeList_Push(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), limit)
45+
46+
// Pops a PyObject from the freelist, returns NULL if the freelist is empty.
47+
#define _Py_FREELIST_POP(TYPE, NAME) \
48+
_Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME))
49+
50+
// Pops a non-PyObject data structure from the freelist, returns NULL if the
51+
// freelist is empty.
52+
#define _Py_FREELIST_POP_MEM(NAME) \
53+
_PyFreeList_PopMem(&_Py_freelists_GET()->NAME)
54+
55+
#define _Py_FREELIST_SIZE(NAME) (int)((_Py_freelists_GET()->NAME).size)
56+
57+
static inline int
58+
_PyFreeList_Push(struct _Py_freelist *fl, void *obj, Py_ssize_t maxsize)
59+
{
60+
if (fl->size < maxsize && fl->size >= 0) {
61+
*(void **)obj = fl->freelist;
62+
fl->freelist = obj;
63+
fl->size++;
64+
OBJECT_STAT_INC(to_freelist);
65+
return 1;
66+
}
67+
return 0;
68+
}
8569

86-
struct _Py_slice_freelist {
87-
#ifdef WITH_FREELISTS
88-
/* Using a cache is very effective since typically only a single slice is
89-
created and then deleted again. */
90-
PySliceObject *slice_cache;
91-
#endif
92-
};
70+
static inline void
71+
_PyFreeList_Free(struct _Py_freelist *fl, void *obj, Py_ssize_t maxsize,
72+
freefunc dofree)
73+
{
74+
if (!_PyFreeList_Push(fl, obj, maxsize)) {
75+
dofree(obj);
76+
}
77+
}
9378

94-
struct _Py_context_freelist {
95-
#ifdef WITH_FREELISTS
96-
// List of free PyContext objects
97-
PyContext *items;
98-
int numfree;
99-
#endif
100-
};
79+
static inline void *
80+
_PyFreeList_PopNoStats(struct _Py_freelist *fl)
81+
{
82+
void *obj = fl->freelist;
83+
if (obj != NULL) {
84+
assert(fl->size > 0);
85+
fl->freelist = *(void **)obj;
86+
fl->size--;
87+
}
88+
return obj;
89+
}
10190

102-
struct _Py_async_gen_freelist {
103-
#ifdef WITH_FREELISTS
104-
/* Freelists boost performance 6-10%; they also reduce memory
105-
fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend
106-
are short-living objects that are instantiated for every
107-
__anext__() call. */
108-
struct _PyAsyncGenWrappedValue* items[_PyAsyncGen_MAXFREELIST];
109-
int numfree;
110-
#endif
111-
};
91+
static inline PyObject *
92+
_PyFreeList_Pop(struct _Py_freelist *fl)
93+
{
94+
PyObject *op = _PyFreeList_PopNoStats(fl);
95+
if (op != NULL) {
96+
OBJECT_STAT_INC(from_freelist);
97+
_Py_NewReference(op);
98+
}
99+
return op;
100+
}
112101

113-
struct _Py_async_gen_asend_freelist {
114-
#ifdef WITH_FREELISTS
115-
struct PyAsyncGenASend* items[_PyAsyncGen_MAXFREELIST];
116-
int numfree;
102+
static inline void *
103+
_PyFreeList_PopMem(struct _Py_freelist *fl)
104+
{
105+
void *op = _PyFreeList_PopNoStats(fl);
106+
if (op != NULL) {
107+
OBJECT_STAT_INC(from_freelist);
108+
}
109+
return op;
110+
}
117111
#endif
118-
};
119-
120-
struct _PyObjectStackChunk;
121-
122-
struct _Py_object_stack_freelist {
123-
struct _PyObjectStackChunk *items;
124-
Py_ssize_t numfree;
125-
};
126-
127-
struct _Py_object_freelists {
128-
struct _Py_float_freelist floats;
129-
struct _Py_tuple_freelist tuples;
130-
struct _Py_list_freelist lists;
131-
struct _Py_dict_freelist dicts;
132-
struct _Py_dictkeys_freelist dictkeys;
133-
struct _Py_slice_freelist slices;
134-
struct _Py_context_freelist contexts;
135-
struct _Py_async_gen_freelist async_gens;
136-
struct _Py_async_gen_asend_freelist async_gen_asends;
137-
struct _Py_object_stack_freelist object_stacks;
138-
};
139112

140-
extern void _PyObject_ClearFreeLists(struct _Py_object_freelists *freelists, int is_finalization);
141-
extern void _PyTuple_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
142-
extern void _PyFloat_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
143-
extern void _PyList_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
144-
extern void _PySlice_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
145-
extern void _PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
146-
extern void _PyAsyncGen_ClearFreeLists(struct _Py_object_freelists *freelists, int is_finalization);
147-
extern void _PyContext_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
148-
extern void _PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
113+
extern void _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization);
149114

150115
#ifdef __cplusplus
151116
}

0 commit comments

Comments
 (0)