Skip to content

Commit a62d16a

Browse files
eendebakptclaude
andcommitted
Avoid Py_None as a fallback sentinel in _PyBytes_FromSequence_lock_held
Use the PyDict_GetItemRef()-style tri-state contract instead: return 1 on success with *result set, 0 to fall back to the slow path, and -1 on error with an exception set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent dc429c4 commit a62d16a

1 file changed

Lines changed: 18 additions & 10 deletions

File tree

Objects/bytesobject.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2981,13 +2981,18 @@ _PyBytes_FromBuffer(PyObject *x)
29812981
return NULL;
29822982
}
29832983

2984-
static PyObject*
2985-
_PyBytes_FromSequence_lock_held(PyObject *x)
2984+
/* Fast path for a list or tuple of ints.
2985+
Return 1 on success (*result set to the new bytes object),
2986+
0 to fall back to the slow path (an item is not an int; no exception
2987+
set), or -1 on error (with an exception set). */
2988+
static int
2989+
_PyBytes_FromSequence_lock_held(PyObject *x, PyObject **result)
29862990
{
2991+
*result = NULL;
29872992
Py_ssize_t size = PySequence_Fast_GET_SIZE(x);
29882993
PyBytesWriter *writer = PyBytesWriter_Create(size);
29892994
if (writer == NULL) {
2990-
return NULL;
2995+
return -1;
29912996
}
29922997
char *str = PyBytesWriter_GetData(writer);
29932998
assert(_PyBytesWriter_GetAllocated(writer) >= size);
@@ -2998,19 +3003,19 @@ _PyBytes_FromSequence_lock_held(PyObject *x)
29983003
if (value == -1 && PyErr_Occurred()) {
29993004
PyBytesWriter_Discard(writer);
30003005
PyErr_Clear();
3001-
/* Py_None as a fallback sentinel to the slow path */
3002-
Py_RETURN_NONE;
3006+
return 0;
30033007
}
30043008

30053009
if (value < 0 || value >= 256) {
30063010
PyErr_SetString(PyExc_ValueError,
30073011
"bytes must be in range(0, 256)");
30083012
PyBytesWriter_Discard(writer);
3009-
return NULL;
3013+
return -1;
30103014
}
30113015
*str++ = (char) value;
30123016
}
3013-
return PyBytesWriter_FinishWithPointer(writer, str);
3017+
*result = PyBytesWriter_FinishWithPointer(writer, str);
3018+
return *result != NULL ? 1 : -1;
30143019
}
30153020

30163021
static PyObject *
@@ -3092,13 +3097,16 @@ PyBytes_FromObject(PyObject *x)
30923097
return _PyBytes_FromBuffer(x);
30933098

30943099
if (PyList_CheckExact(x) || PyTuple_CheckExact(x)) {
3100+
int rc;
30953101
Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST(x);
3096-
result = _PyBytes_FromSequence_lock_held(x);
3102+
rc = _PyBytes_FromSequence_lock_held(x, &result);
30973103
Py_END_CRITICAL_SECTION_SEQUENCE_FAST();
3098-
/* Py_None as a fallback sentinel to the slow path */
3099-
if (result != Py_None) {
3104+
if (rc != 0) {
3105+
/* Success (result is the new bytes object) or error
3106+
(result is NULL with an exception set). */
31003107
return result;
31013108
}
3109+
/* rc == 0: an item is not an int; use the slow path below. */
31023110
}
31033111

31043112
if (!PyUnicode_Check(x)) {

0 commit comments

Comments
 (0)