gh-129813, PEP 782: Use PyBytesWriter in binascii (#138825)

Replace the private _PyBytesWriter API with the new public
PyBytesWriter API.
This commit is contained in:
Victor Stinner 2025-09-13 18:25:16 +02:00 committed by GitHub
parent 805e3368d6
commit ca99af3c5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -205,11 +205,9 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
/*[clinic end generated code: output=e027f8e0b0598742 input=7cafeaf73df63d1c]*/ /*[clinic end generated code: output=e027f8e0b0598742 input=7cafeaf73df63d1c]*/
{ {
const unsigned char *ascii_data; const unsigned char *ascii_data;
unsigned char *bin_data;
int leftbits = 0; int leftbits = 0;
unsigned char this_ch; unsigned char this_ch;
unsigned int leftchar = 0; unsigned int leftchar = 0;
PyObject *rv;
Py_ssize_t ascii_len, bin_len; Py_ssize_t ascii_len, bin_len;
binascii_state *state; binascii_state *state;
@ -223,9 +221,11 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
ascii_len--; ascii_len--;
/* Allocate the buffer */ /* Allocate the buffer */
if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL ) PyBytesWriter *writer = PyBytesWriter_Create(bin_len);
if (writer == NULL) {
return NULL; return NULL;
bin_data = (unsigned char *)PyBytes_AS_STRING(rv); }
unsigned char *bin_data = PyBytesWriter_GetData(writer);
for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) { for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) {
/* XXX is it really best to add NULs if there's no more data */ /* XXX is it really best to add NULs if there's no more data */
@ -245,11 +245,10 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
if ( this_ch < ' ' || this_ch > (' ' + 64)) { if ( this_ch < ' ' || this_ch > (' ' + 64)) {
state = get_binascii_state(module); state = get_binascii_state(module);
if (state == NULL) { if (state == NULL) {
return NULL; goto error;
} }
PyErr_SetString(state->Error, "Illegal char"); PyErr_SetString(state->Error, "Illegal char");
Py_DECREF(rv); goto error;
return NULL;
} }
this_ch = (this_ch - ' ') & 077; this_ch = (this_ch - ' ') & 077;
} }
@ -277,14 +276,17 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
this_ch != '\n' && this_ch != '\r' ) { this_ch != '\n' && this_ch != '\r' ) {
state = get_binascii_state(module); state = get_binascii_state(module);
if (state == NULL) { if (state == NULL) {
return NULL; goto error;
} }
PyErr_SetString(state->Error, "Trailing garbage"); PyErr_SetString(state->Error, "Trailing garbage");
Py_DECREF(rv); goto error;
return NULL;
} }
} }
return rv; return PyBytesWriter_Finish(writer);
error:
PyBytesWriter_Discard(writer);
return NULL;
} }
/*[clinic input] /*[clinic input]
@ -302,16 +304,13 @@ static PyObject *
binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick)
/*[clinic end generated code: output=b1b99de62d9bbeb8 input=beb27822241095cd]*/ /*[clinic end generated code: output=b1b99de62d9bbeb8 input=beb27822241095cd]*/
{ {
unsigned char *ascii_data;
const unsigned char *bin_data; const unsigned char *bin_data;
int leftbits = 0; int leftbits = 0;
unsigned char this_ch; unsigned char this_ch;
unsigned int leftchar = 0; unsigned int leftchar = 0;
binascii_state *state; binascii_state *state;
Py_ssize_t bin_len, out_len; Py_ssize_t bin_len;
_PyBytesWriter writer;
_PyBytesWriter_Init(&writer);
bin_data = data->buf; bin_data = data->buf;
bin_len = data->len; bin_len = data->len;
if ( bin_len > 45 ) { if ( bin_len > 45 ) {
@ -325,10 +324,12 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick)
} }
/* We're lazy and allocate to much (fixed up later) */ /* We're lazy and allocate to much (fixed up later) */
out_len = 2 + (bin_len + 2) / 3 * 4; Py_ssize_t out_len = 2 + (bin_len + 2) / 3 * 4;
ascii_data = _PyBytesWriter_Alloc(&writer, out_len); PyBytesWriter *writer = PyBytesWriter_Create(out_len);
if (ascii_data == NULL) if (writer == NULL) {
return NULL; return NULL;
}
unsigned char *ascii_data = PyBytesWriter_GetData(writer);
/* Store the length */ /* Store the length */
if (backtick && !bin_len) if (backtick && !bin_len)
@ -356,7 +357,7 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick)
} }
*ascii_data++ = '\n'; /* Append a courtesy newline */ *ascii_data++ = '\n'; /* Append a courtesy newline */
return _PyBytesWriter_Finish(&writer, ascii_data); return PyBytesWriter_FinishWithPointer(writer, ascii_data);
} }
/*[clinic input] /*[clinic input]
@ -388,12 +389,11 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode)
/* Allocate the buffer */ /* Allocate the buffer */
Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */
_PyBytesWriter writer; PyBytesWriter *writer = PyBytesWriter_Create(bin_len);
_PyBytesWriter_Init(&writer); if (writer == NULL) {
unsigned char *bin_data = _PyBytesWriter_Alloc(&writer, bin_len);
if (bin_data == NULL)
return NULL; return NULL;
unsigned char *bin_data_start = bin_data; }
unsigned char *bin_data = PyBytesWriter_GetData(writer);
if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') { if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') {
state = get_binascii_state(module); state = get_binascii_state(module);
@ -489,12 +489,14 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode)
state = get_binascii_state(module); state = get_binascii_state(module);
if (state == NULL) { if (state == NULL) {
/* error already set, from get_binascii_state */ /* error already set, from get_binascii_state */
assert(PyErr_Occurred());
} else if (quad_pos == 1) { } else if (quad_pos == 1) {
/* /*
** There is exactly one extra valid, non-padding, base64 character. ** There is exactly one extra valid, non-padding, base64 character.
** This is an invalid length, as there is no possible input that ** This is an invalid length, as there is no possible input that
** could encoded into such a base64 string. ** could encoded into such a base64 string.
*/ */
unsigned char *bin_data_start = PyBytesWriter_GetData(writer);
PyErr_Format(state->Error, PyErr_Format(state->Error,
"Invalid base64-encoded string: " "Invalid base64-encoded string: "
"number of data characters (%zd) cannot be 1 more " "number of data characters (%zd) cannot be 1 more "
@ -503,13 +505,15 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode)
} else { } else {
PyErr_SetString(state->Error, "Incorrect padding"); PyErr_SetString(state->Error, "Incorrect padding");
} }
error_end: goto error_end;
_PyBytesWriter_Dealloc(&writer);
return NULL;
} }
done: done:
return _PyBytesWriter_Finish(&writer, bin_data); return PyBytesWriter_FinishWithPointer(writer, bin_data);
error_end:
PyBytesWriter_Discard(writer);
return NULL;
} }
@ -528,18 +532,15 @@ static PyObject *
binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline) binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline)
/*[clinic end generated code: output=4ad62c8e8485d3b3 input=0e20ff59c5f2e3e1]*/ /*[clinic end generated code: output=4ad62c8e8485d3b3 input=0e20ff59c5f2e3e1]*/
{ {
unsigned char *ascii_data;
const unsigned char *bin_data; const unsigned char *bin_data;
int leftbits = 0; int leftbits = 0;
unsigned char this_ch; unsigned char this_ch;
unsigned int leftchar = 0; unsigned int leftchar = 0;
Py_ssize_t bin_len, out_len; Py_ssize_t bin_len;
_PyBytesWriter writer;
binascii_state *state; binascii_state *state;
bin_data = data->buf; bin_data = data->buf;
bin_len = data->len; bin_len = data->len;
_PyBytesWriter_Init(&writer);
assert(bin_len >= 0); assert(bin_len >= 0);
@ -555,12 +556,15 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline)
/* We're lazy and allocate too much (fixed up later). /* We're lazy and allocate too much (fixed up later).
"+2" leaves room for up to two pad characters. "+2" leaves room for up to two pad characters.
Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */ Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */
out_len = bin_len*2 + 2; Py_ssize_t out_len = bin_len*2 + 2;
if (newline) if (newline) {
out_len++; out_len++;
ascii_data = _PyBytesWriter_Alloc(&writer, out_len); }
if (ascii_data == NULL) PyBytesWriter *writer = PyBytesWriter_Create(out_len);
if (writer == NULL) {
return NULL; return NULL;
}
unsigned char *ascii_data = PyBytesWriter_GetData(writer);
for( ; bin_len > 0 ; bin_len--, bin_data++ ) { for( ; bin_len > 0 ; bin_len--, bin_data++ ) {
/* Shift the data into our buffer */ /* Shift the data into our buffer */
@ -585,7 +589,7 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline)
if (newline) if (newline)
*ascii_data++ = '\n'; /* Append a courtesy newline */ *ascii_data++ = '\n'; /* Append a courtesy newline */
return _PyBytesWriter_Finish(&writer, ascii_data); return PyBytesWriter_FinishWithPointer(writer, ascii_data);
} }
@ -887,8 +891,6 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
{ {
const char* argbuf; const char* argbuf;
Py_ssize_t arglen; Py_ssize_t arglen;
PyObject *retval;
char* retbuf;
Py_ssize_t i, j; Py_ssize_t i, j;
binascii_state *state; binascii_state *state;
@ -910,10 +912,11 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
return NULL; return NULL;
} }
retval = PyBytes_FromStringAndSize(NULL, (arglen/2)); PyBytesWriter *writer = PyBytesWriter_Create(arglen/2);
if (!retval) if (writer == NULL) {
return NULL; return NULL;
retbuf = PyBytes_AS_STRING(retval); }
char *retbuf = PyBytesWriter_GetData(writer);
for (i=j=0; i < arglen; i += 2) { for (i=j=0; i < arglen; i += 2) {
unsigned int top = _PyLong_DigitValue[Py_CHARMASK(argbuf[i])]; unsigned int top = _PyLong_DigitValue[Py_CHARMASK(argbuf[i])];
@ -921,18 +924,18 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
if (top >= 16 || bot >= 16) { if (top >= 16 || bot >= 16) {
state = get_binascii_state(module); state = get_binascii_state(module);
if (state == NULL) { if (state == NULL) {
return NULL; goto error;
} }
PyErr_SetString(state->Error, PyErr_SetString(state->Error,
"Non-hexadecimal digit found"); "Non-hexadecimal digit found");
goto finally; goto error;
} }
retbuf[j++] = (top << 4) + bot; retbuf[j++] = (top << 4) + bot;
} }
return retval; return PyBytesWriter_Finish(writer);
finally: error:
Py_DECREF(retval); PyBytesWriter_Discard(writer);
return NULL; return NULL;
} }