Skip to content

Commit 2233973

Browse files
Merge branch 'main' into fuzz_pycompile.dict
2 parents c4207ee + b062f39 commit 2233973

Some content is hidden

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

57 files changed

+1569
-1527
lines changed

.github/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ updates:
1212
update-types:
1313
- "version-update:semver-minor"
1414
- "version-update:semver-patch"
15+
groups:
16+
actions:
17+
patterns:
18+
- "*"
1519
cooldown:
1620
# https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
1721
# Cooldowns protect against supply chain attacks by avoiding the

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ jobs:
475475
-x test_subprocess \
476476
-x test_signal \
477477
-x test_sysconfig
478-
- uses: actions/upload-artifact@v6
478+
- uses: actions/upload-artifact@v7
479479
if: always()
480480
with:
481481
name: hypothesis-example-db

.github/workflows/reusable-check-c-api-docs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515
runs-on: ubuntu-latest
1616
timeout-minutes: 5
1717
steps:
18-
- uses: actions/checkout@v4
18+
- uses: actions/checkout@v6
1919
with:
2020
persist-credentials: false
21-
- uses: actions/setup-python@v5
21+
- uses: actions/setup-python@v6
2222
with:
2323
python-version: '3.x'
2424
- name: Check for undocumented C APIs

.github/workflows/reusable-cifuzz.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
sanitizer: ${{ inputs.sanitizer }}
3535
- name: Upload crash
3636
if: failure() && steps.build.outcome == 'success'
37-
uses: actions/upload-artifact@v6
37+
uses: actions/upload-artifact@v7
3838
with:
3939
name: ${{ inputs.sanitizer }}-artifacts
4040
path: ./out/artifacts

.github/workflows/reusable-san.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000
9797
- name: Archive logs
9898
if: always()
99-
uses: actions/upload-artifact@v6
99+
uses: actions/upload-artifact@v7
100100
with:
101101
name: >-
102102
${{ inputs.sanitizer }}-logs-${{

.github/workflows/stale.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
steps:
1616
- name: "Check PRs"
17-
uses: actions/stale@v9
17+
uses: actions/stale@v10
1818
with:
1919
repo-token: ${{ secrets.GITHUB_TOKEN }}
2020
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'

Doc/c-api/bytes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,17 @@ Getters
371371
372372
Get the writer size.
373373
374+
The function cannot fail.
375+
374376
.. c:function:: void* PyBytesWriter_GetData(PyBytesWriter *writer)
375377
376378
Get the writer data: start of the internal buffer.
377379
378380
The pointer is valid until :c:func:`PyBytesWriter_Finish` or
379381
:c:func:`PyBytesWriter_Discard` is called on *writer*.
380382
383+
The function cannot fail.
384+
381385
382386
Low-level API
383387
^^^^^^^^^^^^^

Doc/howto/instrumentation.rst

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,84 @@ Available static markers
341341
.. versionadded:: 3.8
342342

343343

344+
C Entry Points
345+
^^^^^^^^^^^^^^
346+
347+
To simplify triggering of DTrace markers, Python's C API comes with a number
348+
of helper functions that mirror each static marker. On builds of Python without
349+
DTrace enabled, these do nothing.
350+
351+
In general, it is not necessary to call these yourself, as Python will do
352+
it for you.
353+
354+
.. list-table::
355+
:widths: 50 25 25
356+
:header-rows: 1
357+
358+
* * C API Function
359+
* Static Marker
360+
* Notes
361+
* * .. c:function:: void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2)
362+
* :c:func:`!line`
363+
*
364+
* * .. c:function:: void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2)
365+
* :c:func:`!function__entry`
366+
*
367+
* * .. c:function:: void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2)
368+
* :c:func:`!function__return`
369+
*
370+
* * .. c:function:: void PyDTrace_GC_START(int arg0)
371+
* :c:func:`!gc__start`
372+
*
373+
* * .. c:function:: void PyDTrace_GC_DONE(Py_ssize_t arg0)
374+
* :c:func:`!gc__done`
375+
*
376+
* * .. c:function:: void PyDTrace_INSTANCE_NEW_START(int arg0)
377+
* :c:func:`!instance__new__start`
378+
* Not used by Python
379+
* * .. c:function:: void PyDTrace_INSTANCE_NEW_DONE(int arg0)
380+
* :c:func:`!instance__new__done`
381+
* Not used by Python
382+
* * .. c:function:: void PyDTrace_INSTANCE_DELETE_START(int arg0)
383+
* :c:func:`!instance__delete__start`
384+
* Not used by Python
385+
* * .. c:function:: void PyDTrace_INSTANCE_DELETE_DONE(int arg0)
386+
* :c:func:`!instance__delete__done`
387+
* Not used by Python
388+
* * .. c:function:: void PyDTrace_IMPORT_FIND_LOAD_START(const char *arg0)
389+
* :c:func:`!import__find__load__start`
390+
*
391+
* * .. c:function:: void PyDTrace_IMPORT_FIND_LOAD_DONE(const char *arg0, int arg1)
392+
* :c:func:`!import__find__load__done`
393+
*
394+
* * .. c:function:: void PyDTrace_AUDIT(const char *arg0, void *arg1)
395+
* :c:func:`!audit`
396+
*
397+
398+
399+
C Probing Checks
400+
^^^^^^^^^^^^^^^^
401+
402+
.. c:function:: int PyDTrace_LINE_ENABLED(void)
403+
.. c:function:: int PyDTrace_FUNCTION_ENTRY_ENABLED(void)
404+
.. c:function:: int PyDTrace_FUNCTION_RETURN_ENABLED(void)
405+
.. c:function:: int PyDTrace_GC_START_ENABLED(void)
406+
.. c:function:: int PyDTrace_GC_DONE_ENABLED(void)
407+
.. c:function:: int PyDTrace_INSTANCE_NEW_START_ENABLED(void)
408+
.. c:function:: int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void)
409+
.. c:function:: int PyDTrace_INSTANCE_DELETE_START_ENABLED(void)
410+
.. c:function:: int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void)
411+
.. c:function:: int PyDTrace_IMPORT_FIND_LOAD_START_ENABLED(void)
412+
.. c:function:: int PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED(void)
413+
.. c:function:: int PyDTrace_AUDIT_ENABLED(void)
414+
415+
All calls to ``PyDTrace`` functions must be guarded by a call to one
416+
of these functions. This allows Python to minimize performance impact
417+
when probing is disabled.
418+
419+
On builds without DTrace enabled, these functions do nothing and return
420+
``0``.
421+
344422
SystemTap Tapsets
345423
-----------------
346424

Doc/library/stdtypes.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ Mutable sequence types also support the following methods:
12861286
:no-typesetting:
12871287
.. method:: sequence.append(value, /)
12881288

1289-
Append *value* to the end of the sequence
1289+
Append *value* to the end of the sequence.
12901290
This is equivalent to writing ``seq[len(seq):len(seq)] = [value]``.
12911291

12921292
.. method:: bytearray.clear()
@@ -3514,6 +3514,11 @@ The representation of bytearray objects uses the bytes literal format
35143514
``bytearray([46, 46, 46])``. You can always convert a bytearray object into
35153515
a list of integers using ``list(b)``.
35163516

3517+
.. seealso::
3518+
3519+
For detailed information on thread-safety guarantees for :class:`bytearray`
3520+
objects, see :ref:`thread-safety-bytearray`.
3521+
35173522

35183523
.. _bytes-methods:
35193524

Doc/library/threadsafety.rst

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,104 @@ atomic:
447447
448448
Consider external synchronization when sharing :class:`set` instances
449449
across threads. See :ref:`freethreading-python-howto` for more information.
450+
451+
452+
.. _thread-safety-bytearray:
453+
454+
Thread safety for bytearray objects
455+
===================================
456+
457+
The :func:`len` function is lock-free and :term:`atomic <atomic operation>`.
458+
459+
Concatenation and comparisons use the buffer protocol, which prevents
460+
resizing but does not hold the per-object lock. These operations may
461+
observe intermediate states from concurrent modifications:
462+
463+
.. code-block::
464+
:class: maybe
465+
466+
ba + other # may observe concurrent writes
467+
ba == other # may observe concurrent writes
468+
ba < other # may observe concurrent writes
469+
470+
All other operations from here on hold the per-object lock.
471+
472+
Reading a single element or slice is safe to call from multiple threads:
473+
474+
.. code-block::
475+
:class: good
476+
477+
ba[i] # bytearray.__getitem__
478+
ba[i:j] # slice
479+
480+
The following operations are safe to call from multiple threads and will
481+
not corrupt the bytearray:
482+
483+
.. code-block::
484+
:class: good
485+
486+
ba[i] = x # write single byte
487+
ba[i:j] = values # write slice
488+
ba.append(x) # append single byte
489+
ba.extend(other) # extend with iterable
490+
ba.insert(i, x) # insert single byte
491+
ba.pop() # remove and return last byte
492+
ba.pop(i) # remove and return byte at index
493+
ba.remove(x) # remove first occurrence
494+
ba.reverse() # reverse in place
495+
ba.clear() # remove all bytes
496+
497+
Slice assignment locks both objects when *values* is a :class:`bytearray`:
498+
499+
.. code-block::
500+
:class: good
501+
502+
ba[i:j] = other_bytearray # both locked
503+
504+
The following operations return new objects and hold the per-object lock
505+
for the duration:
506+
507+
.. code-block::
508+
:class: good
509+
510+
ba.copy() # returns a shallow copy
511+
ba * n # repeat into new bytearray
512+
513+
The membership test holds the lock for its duration:
514+
515+
.. code-block::
516+
:class: good
517+
518+
x in ba # bytearray.__contains__
519+
520+
All other bytearray methods (such as :meth:`~bytearray.find`,
521+
:meth:`~bytearray.replace`, :meth:`~bytearray.split`,
522+
:meth:`~bytearray.decode`, etc.) hold the per-object lock for their
523+
duration.
524+
525+
Operations that involve multiple accesses, as well as iteration, are never
526+
atomic:
527+
528+
.. code-block::
529+
:class: bad
530+
531+
# NOT atomic: check-then-act
532+
if x in ba:
533+
ba.remove(x)
534+
535+
# NOT thread-safe: iteration while modifying
536+
for byte in ba:
537+
process(byte) # another thread may modify ba
538+
539+
To safely iterate over a bytearray that may be modified by another
540+
thread, iterate over a copy:
541+
542+
.. code-block::
543+
:class: good
544+
545+
# Make a copy to iterate safely
546+
for byte in ba.copy():
547+
process(byte)
548+
549+
Consider external synchronization when sharing :class:`bytearray` instances
550+
across threads. See :ref:`freethreading-python-howto` for more information.

0 commit comments

Comments
 (0)