Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion Doc/data/threadsafety.dat
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,33 @@ PyByteArray_GET_SIZE:atomic:

# Raw data - no locking; mutating it is unsafe if the bytearray object is shared between threads
PyByteArray_AsString:compatible:
PyByteArray_AS_STRING:compatible:
PyByteArray_AS_STRING:compatible:

# Capsule objects (Doc/c-api/capsule.rst)

# Type check - read ob_type pointer, always safe
PyCapsule_CheckExact:atomic:

# Creation - pure allocation, no shared state
PyCapsule_New:atomic:

# Validation - reads pointer and name fields; safe on distinct objects
PyCapsule_IsValid:distinct:

# Getters - read struct fields; safe on distinct objects but
# concurrent access to the same capsule requires external synchronization
PyCapsule_GetPointer:distinct:
PyCapsule_GetName:distinct:
PyCapsule_GetDestructor:distinct:
PyCapsule_GetContext:distinct:

# Setters - write struct fields; safe on distinct objects but
# concurrent access to the same capsule requires external synchronization
PyCapsule_SetPointer:distinct:
PyCapsule_SetName:distinct:
PyCapsule_SetDestructor:distinct:
PyCapsule_SetContext:distinct:

# Import - looks up a capsule from a module attribute and
# calls PyCapsule_GetPointer; may call arbitrary code
PyCapsule_Import:compatible:
8 changes: 4 additions & 4 deletions Lib/profiling/sampling/stack_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ def __init__(self, sample_interval_usec, *, skip_idle=False):
self.sample_interval_usec = sample_interval_usec
self.skip_idle = skip_idle

def collect(self, stack_frames, timestamps_us=None, skip_idle=False):
def collect(self, stack_frames, timestamps_us=None):
weight = len(timestamps_us) if timestamps_us else 1
for frames, thread_id in self._iter_stacks(stack_frames, skip_idle=skip_idle):
for frames, thread_id in self._iter_stacks(stack_frames, skip_idle=self.skip_idle):
self.process_frames(frames, thread_id, weight=weight)

def process_frames(self, frames, thread_id, weight=1):
Expand Down Expand Up @@ -88,7 +88,7 @@ def __init__(self, *args, **kwargs):
# Per-thread statistics
self.per_thread_stats = {} # {thread_id: {has_gil, on_cpu, gil_requested, unknown, has_exception, total, gc_samples}}

def collect(self, stack_frames, timestamps_us=None, skip_idle=False):
def collect(self, stack_frames, timestamps_us=None):
"""Override to track thread status statistics before processing frames."""
# Weight is number of timestamps (samples with identical stack)
weight = len(timestamps_us) if timestamps_us else 1
Expand Down Expand Up @@ -123,7 +123,7 @@ def collect(self, stack_frames, timestamps_us=None, skip_idle=False):
self.per_thread_stats[thread_id][key] += value * weight

# Call parent collect to process frames
super().collect(stack_frames, timestamps_us, skip_idle=skip_idle)
super().collect(stack_frames, timestamps_us)

def set_stats(self, sample_interval_usec, duration_sec, sample_rate,
error_rate=None, missed_samples=None, mode=None):
Expand Down
22 changes: 22 additions & 0 deletions Lib/test/test_descr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1803,6 +1803,28 @@ class SubSpam(spam.spamlist): pass
spam_cm.__get__(None, list)
self.assertEqual(str(cm.exception), expected_errmsg)

@support.cpython_only
def test_method_get_meth_method_invalid_type(self):
# gh-146615: method_get() for METH_METHOD descriptors used to pass
# Py_TYPE(type)->tp_name as the %V fallback instead of the separate
# %s argument, causing a missing argument for %s and a crash.
# Verify the error message is correct when __get__() is called with a
# non-type as the second argument.
#
# METH_METHOD|METH_FASTCALL|METH_KEYWORDS is the only flag combination
# that enters the affected branch in method_get().
import io

obj = io.StringIO()
descr = io.TextIOBase.read

with self.assertRaises(TypeError) as cm:
descr.__get__(obj, "not_a_type")
self.assertEqual(
str(cm.exception),
"descriptor 'read' needs a type, not 'str', as arg 2",
)

def test_staticmethods(self):
# Testing static methods...
class C(object):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix a crash in :meth:`~object.__get__` for :c:expr:`METH_METHOD` descriptors
when an invalid (non-type) object is passed as the second argument.
Patch by Steven Sun.
6 changes: 3 additions & 3 deletions Modules/_asynciomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2244,7 +2244,7 @@ enter_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task)
PyExc_RuntimeError,
"Cannot enter into task %R while another " \
"task %R is being executed.",
task, ts->asyncio_running_task, NULL);
task, ts->asyncio_running_task);
return -1;
}

Expand All @@ -2265,7 +2265,7 @@ leave_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task)
PyExc_RuntimeError,
"Invalid attempt to leave task %R while " \
"task %R is entered.",
task, ts->asyncio_running_task ? ts->asyncio_running_task : Py_None, NULL);
task, ts->asyncio_running_task ? ts->asyncio_running_task : Py_None);
return -1;
}
Py_CLEAR(ts->asyncio_running_task);
Expand Down Expand Up @@ -2328,7 +2328,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
self->task_log_destroy_pending = 0;
PyErr_Format(PyExc_TypeError,
"a coroutine was expected, got %R",
coro, NULL);
coro);
return -1;
}

Expand Down
2 changes: 1 addition & 1 deletion Modules/_remote_debugging/asyncio.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ parse_task_name(
set_exception_cause(unwinder, PyExc_RuntimeError, "Task name PyLong parsing failed");
return NULL;
}
return PyUnicode_FromFormat("Task-%d", res);
return PyUnicode_FromFormat("Task-%ld", res);
}

if(!(GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_UNICODE_SUBCLASS)) {
Expand Down
14 changes: 5 additions & 9 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ fill_and_set_sslerror(_sslmodulestate *state,
}
else {
if (PyUnicodeWriter_Format(
writer, "unknown error (0x%x)", errcode) < 0) {
writer, "unknown error (0x%lx)", errcode) < 0) {
goto fail;
}
}
Expand Down Expand Up @@ -4016,15 +4016,11 @@ _ssl__SSLContext_verify_flags_set_impl(PySSLContext *self, PyObject *value)
static int
set_min_max_proto_version(PySSLContext *self, PyObject *arg, int what)
{
long v;
int v;
int result;

if (!PyArg_Parse(arg, "l", &v))
if (!PyArg_Parse(arg, "i", &v))
return -1;
if (v > INT_MAX) {
PyErr_SetString(PyExc_OverflowError, "Option is too long");
return -1;
}

switch(self->protocol) {
case PY_SSL_VERSION_TLS_CLIENT: _Py_FALLTHROUGH;
Expand Down Expand Up @@ -4059,7 +4055,7 @@ set_min_max_proto_version(PySSLContext *self, PyObject *arg, int what)
break;
default:
PyErr_Format(PyExc_ValueError,
"Unsupported TLS/SSL version 0x%x", v);
"Unsupported TLS/SSL version 0x%x", (unsigned)v);
return -1;
}

Expand Down Expand Up @@ -4093,7 +4089,7 @@ set_min_max_proto_version(PySSLContext *self, PyObject *arg, int what)
}
if (result == 0) {
PyErr_Format(PyExc_ValueError,
"Unsupported protocol version 0x%x", v);
"Unsupported protocol version 0x%x", (unsigned)v);
return -1;
}
return 0;
Expand Down
4 changes: 2 additions & 2 deletions Modules/_testcapi/watchers.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ add_code_watcher(PyObject *self, PyObject *which_watcher)
watcher_id = PyCode_AddWatcher(error_code_event_handler);
}
else {
PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l);
PyErr_Format(PyExc_ValueError, "invalid watcher %ld", which_l);
return NULL;
}
if (watcher_id < 0) {
Expand Down Expand Up @@ -673,7 +673,7 @@ add_context_watcher(PyObject *self, PyObject *which_watcher)
assert(PyLong_Check(which_watcher));
long which_l = PyLong_AsLong(which_watcher);
if (which_l < 0 || which_l >= (long)Py_ARRAY_LENGTH(callbacks)) {
PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l);
PyErr_Format(PyExc_ValueError, "invalid watcher %ld", which_l);
return NULL;
}
int watcher_id = PyContext_AddWatcher(callbacks[which_l]);
Expand Down
4 changes: 2 additions & 2 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored))
do { \
if (EXPECTED != sizeof(TYPE)) { \
PyErr_Format(get_testerror(self), \
"sizeof(%s) = %u instead of %u", \
#TYPE, sizeof(TYPE), EXPECTED); \
"sizeof(%s) = %zu instead of %u", \
#TYPE, sizeof(TYPE), (unsigned)(EXPECTED)); \
return (PyObject*)NULL; \
} \
} while (0)
Expand Down
8 changes: 4 additions & 4 deletions Modules/_testinternalcapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,14 +417,14 @@ test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
if (u16 != UINT16_C(0x1234)) {
PyErr_Format(PyExc_AssertionError,
"_Py_bswap16(0x3412) returns %u", u16);
"_Py_bswap16(0x3412) returns %d", u16);
return NULL;
}

uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
if (u32 != UINT32_C(0x12345678)) {
PyErr_Format(PyExc_AssertionError,
"_Py_bswap32(0x78563412) returns %lu", u32);
"_Py_bswap32(0x78563412) returns %u", u32);
return NULL;
}

Expand Down Expand Up @@ -703,7 +703,7 @@ test_edit_cost(PyObject *self, PyObject *Py_UNUSED(args))

static int
check_bytes_find(const char *haystack0, const char *needle0,
int offset, Py_ssize_t expected)
Py_ssize_t offset, Py_ssize_t expected)
{
Py_ssize_t len_haystack = strlen(haystack0);
Py_ssize_t len_needle = strlen(needle0);
Expand Down Expand Up @@ -1158,7 +1158,7 @@ get_interp_settings(PyObject *self, PyObject *args)
}
else {
PyErr_Format(PyExc_NotImplementedError,
"%zd", interpid);
"%d", interpid);
return NULL;
}
assert(interp != NULL);
Expand Down
2 changes: 1 addition & 1 deletion Modules/_zoneinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
}

if (!PyTuple_CheckExact(data_tuple)) {
PyErr_Format(PyExc_TypeError, "Invalid data result type: %r",
PyErr_Format(PyExc_TypeError, "Invalid data result type: %R",
data_tuple);
goto error;
}
Expand Down
4 changes: 2 additions & 2 deletions Modules/binascii.c
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,7 @@ binascii_a2b_base85_impl(PyObject *module, Py_buffer *data,
state = get_binascii_state(module);
if (state != NULL) {
PyErr_Format(state->Error,
"Base85 overflow in hunk starting at byte %d",
"Base85 overflow in hunk starting at byte %zd",
(data->len - ascii_len) / 5 * 5);
}
goto error;
Expand All @@ -1361,7 +1361,7 @@ binascii_a2b_base85_impl(PyObject *module, Py_buffer *data,
else {
state = get_binascii_state(module);
if (state != NULL) {
PyErr_Format(state->Error, "bad Base85 character at position %d",
PyErr_Format(state->Error, "bad Base85 character at position %zd",
data->len - ascii_len);
}
goto error;
Expand Down
3 changes: 1 addition & 2 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3357,8 +3357,7 @@ sock_setsockopt(PyObject *self, PyObject *args)
arglen = PyTuple_Size(args);
if (arglen == 3 && optval == Py_None) {
PyErr_Format(PyExc_TypeError,
"setsockopt() requires 4 arguments when the third argument is None",
arglen);
"setsockopt() requires 4 arguments when the third argument is None");
return NULL;
}
if (arglen == 4 && optval != Py_None) {
Expand Down
4 changes: 2 additions & 2 deletions Objects/descrobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ method_get(PyObject *self, PyObject *obj, PyObject *type)
} else {
PyErr_Format(PyExc_TypeError,
"descriptor '%V' needs a type, not '%s', as arg 2",
descr_name((PyDescrObject *)descr),
descr_name((PyDescrObject *)descr), "?",
Py_TYPE(type)->tp_name);
return NULL;
}
Expand Down Expand Up @@ -1610,7 +1610,7 @@ property_set_name(PyObject *self, PyObject *args) {
if (PyTuple_GET_SIZE(args) != 2) {
PyErr_Format(
PyExc_TypeError,
"__set_name__() takes 2 positional arguments but %d were given",
"__set_name__() takes 2 positional arguments but %zd were given",
PyTuple_GET_SIZE(args));
return NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion Objects/enumobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ enumerate_vectorcall(PyObject *type, PyObject *const *args,
}

PyErr_Format(PyExc_TypeError,
"enumerate() takes at most 2 arguments (%d given)", nargs + nkwargs);
"enumerate() takes at most 2 arguments (%zd given)", nargs + nkwargs);
return NULL;
}

Expand Down
4 changes: 2 additions & 2 deletions Objects/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (!PyExceptionInstance_Check(exc)) {
PyErr_Format(
PyExc_ValueError,
"Item %d of second argument (exceptions) is not an exception",
"Item %zd of second argument (exceptions) is not an exception",
i);
goto error;
}
Expand Down Expand Up @@ -1714,7 +1714,7 @@ PyUnstable_Exc_PrepReraiseStar(PyObject *orig, PyObject *excs)
PyObject *exc = PyList_GET_ITEM(excs, i);
if (exc == NULL || !(PyExceptionInstance_Check(exc) || Py_IsNone(exc))) {
PyErr_Format(PyExc_TypeError,
"item %d of excs is not an exception", i);
"item %zd of excs is not an exception", i);
return NULL;
}
}
Expand Down
4 changes: 2 additions & 2 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ func_set_code(PyObject *self, PyObject *value, void *Py_UNUSED(ignored))
if (nclosure != nfree) {
PyErr_Format(PyExc_ValueError,
"%U() requires a code object with %zd free vars,"
" not %zd",
" not %d",
op->func_name,
nclosure, nfree);
return -1;
Expand Down Expand Up @@ -1044,7 +1044,7 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure);
if (code->co_nfreevars != nclosure)
return PyErr_Format(PyExc_ValueError,
"%U requires closure of length %zd, not %zd",
"%U requires closure of length %d, not %zd",
code->co_name, code->co_nfreevars, nclosure);
if (nclosure) {
Py_ssize_t i;
Expand Down
2 changes: 1 addition & 1 deletion Objects/memoryobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2472,7 +2472,7 @@ ptr_from_tuple(const Py_buffer *view, PyObject *tup)

if (nindices > view->ndim) {
PyErr_Format(PyExc_TypeError,
"cannot index %zd-dimension view with %zd-element tuple",
"cannot index %d-dimension view with %zd-element tuple",
view->ndim, nindices);
return NULL;
}
Expand Down
8 changes: 4 additions & 4 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5184,28 +5184,28 @@ check_basicsize_includes_size_and_offsets(PyTypeObject* type)

if (type->tp_base && type->tp_base->tp_basicsize > type->tp_basicsize) {
PyErr_Format(PyExc_TypeError,
"tp_basicsize for type '%s' (%d) is too small for base '%s' (%d)",
"tp_basicsize for type '%s' (%zd) is too small for base '%s' (%zd)",
type->tp_name, type->tp_basicsize,
type->tp_base->tp_name, type->tp_base->tp_basicsize);
return 0;
}
if (type->tp_weaklistoffset + (Py_ssize_t)sizeof(PyObject*) > max) {
PyErr_Format(PyExc_TypeError,
"weaklist offset %d is out of bounds for type '%s' (tp_basicsize = %d)",
"weaklist offset %zd is out of bounds for type '%s' (tp_basicsize = %zd)",
type->tp_weaklistoffset,
type->tp_name, type->tp_basicsize);
return 0;
}
if (type->tp_dictoffset + (Py_ssize_t)sizeof(PyObject*) > max) {
PyErr_Format(PyExc_TypeError,
"dict offset %d is out of bounds for type '%s' (tp_basicsize = %d)",
"dict offset %zd is out of bounds for type '%s' (tp_basicsize = %zd)",
type->tp_dictoffset,
type->tp_name, type->tp_basicsize);
return 0;
}
if (type->tp_vectorcall_offset + (Py_ssize_t)sizeof(vectorcallfunc*) > max) {
PyErr_Format(PyExc_TypeError,
"vectorcall offset %d is out of bounds for type '%s' (tp_basicsize = %d)",
"vectorcall offset %zd is out of bounds for type '%s' (tp_basicsize = %zd)",
type->tp_vectorcall_offset,
type->tp_name, type->tp_basicsize);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion Objects/typevarobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ typevar_typing_prepare_subst_impl(typevarobject *self, PyObject *alias,
}
Py_DECREF(params);
PyErr_Format(PyExc_TypeError,
"Too few arguments for %S; actual %d, expected at least %d",
"Too few arguments for %S; actual %zd, expected at least %zd",
alias, args_len, i + 1);
return NULL;
}
Expand Down
Loading
Loading