]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-129813, PEP 782: Use PyBytesWriter in binascii (#138825)
authorVictor Stinner <vstinner@python.org>
Sat, 13 Sep 2025 16:25:16 +0000 (18:25 +0200)
committerGitHub <noreply@github.com>
Sat, 13 Sep 2025 16:25:16 +0000 (18:25 +0200)
Replace the private _PyBytesWriter API with the new public
PyBytesWriter API.

Modules/binascii.c

index c70f9f88afe14d71d6205e4985f44cb261845fc4..13e4bc5be03ebdc81f959567e100ddeee9a00c1e 100644 (file)
@@ -205,11 +205,9 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
 /*[clinic end generated code: output=e027f8e0b0598742 input=7cafeaf73df63d1c]*/
 {
     const unsigned char *ascii_data;
-    unsigned char *bin_data;
     int leftbits = 0;
     unsigned char this_ch;
     unsigned int leftchar = 0;
-    PyObject *rv;
     Py_ssize_t ascii_len, bin_len;
     binascii_state *state;
 
@@ -223,9 +221,11 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
     ascii_len--;
 
     /* Allocate the buffer */
-    if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL )
+    PyBytesWriter *writer = PyBytesWriter_Create(bin_len);
+    if (writer == 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++ ) {
         /* 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)) {
                 state = get_binascii_state(module);
                 if (state == NULL) {
-                    return NULL;
+                    goto error;
                 }
                 PyErr_SetString(state->Error, "Illegal char");
-                Py_DECREF(rv);
-                return NULL;
+                goto error;
             }
             this_ch = (this_ch - ' ') & 077;
         }
@@ -277,14 +276,17 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data)
              this_ch != '\n' && this_ch != '\r' ) {
             state = get_binascii_state(module);
             if (state == NULL) {
-                return NULL;
+                goto error;
             }
             PyErr_SetString(state->Error, "Trailing garbage");
-            Py_DECREF(rv);
-            return NULL;
+            goto error;
         }
     }
-    return rv;
+    return PyBytesWriter_Finish(writer);
+
+error:
+    PyBytesWriter_Discard(writer);
+    return NULL;
 }
 
 /*[clinic input]
@@ -302,16 +304,13 @@ static PyObject *
 binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick)
 /*[clinic end generated code: output=b1b99de62d9bbeb8 input=beb27822241095cd]*/
 {
-    unsigned char *ascii_data;
     const unsigned char *bin_data;
     int leftbits = 0;
     unsigned char this_ch;
     unsigned int leftchar = 0;
     binascii_state *state;
-    Py_ssize_t bin_len, out_len;
-    _PyBytesWriter writer;
+    Py_ssize_t bin_len;
 
-    _PyBytesWriter_Init(&writer);
     bin_data = data->buf;
     bin_len = data->len;
     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) */
-    out_len = 2 + (bin_len + 2) / 3 * 4;
-    ascii_data = _PyBytesWriter_Alloc(&writer, out_len);
-    if (ascii_data == NULL)
+    Py_ssize_t out_len = 2 + (bin_len + 2) / 3 * 4;
+    PyBytesWriter *writer = PyBytesWriter_Create(out_len);
+    if (writer == NULL) {
         return NULL;
+    }
+    unsigned char *ascii_data = PyBytesWriter_GetData(writer);
 
     /* Store the length */
     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 */
 
-    return _PyBytesWriter_Finish(&writer, ascii_data);
+    return PyBytesWriter_FinishWithPointer(writer, ascii_data);
 }
 
 /*[clinic input]
@@ -388,12 +389,11 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode)
 
     /* Allocate the buffer */
     Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */
-    _PyBytesWriter writer;
-    _PyBytesWriter_Init(&writer);
-    unsigned char *bin_data = _PyBytesWriter_Alloc(&writer, bin_len);
-    if (bin_data == NULL)
+    PyBytesWriter *writer = PyBytesWriter_Create(bin_len);
+    if (writer == 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] == '=') {
         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);
         if (state == NULL) {
             /* error already set, from get_binascii_state */
+            assert(PyErr_Occurred());
         } else if (quad_pos == 1) {
             /*
             ** There is exactly one extra valid, non-padding, base64 character.
             ** This is an invalid length, as there is no possible input that
             ** could encoded into such a base64 string.
             */
+            unsigned char *bin_data_start = PyBytesWriter_GetData(writer);
             PyErr_Format(state->Error,
                          "Invalid base64-encoded string: "
                          "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 {
             PyErr_SetString(state->Error, "Incorrect padding");
         }
-        error_end:
-        _PyBytesWriter_Dealloc(&writer);
-        return NULL;
+        goto error_end;
     }
 
 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)
 /*[clinic end generated code: output=4ad62c8e8485d3b3 input=0e20ff59c5f2e3e1]*/
 {
-    unsigned char *ascii_data;
     const unsigned char *bin_data;
     int leftbits = 0;
     unsigned char this_ch;
     unsigned int leftchar = 0;
-    Py_ssize_t bin_len, out_len;
-    _PyBytesWriter writer;
+    Py_ssize_t bin_len;
     binascii_state *state;
 
     bin_data = data->buf;
     bin_len = data->len;
-    _PyBytesWriter_Init(&writer);
 
     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).
        "+2" leaves room for up to two pad characters.
        Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */
-    out_len = bin_len*2 + 2;
-    if (newline)
+    Py_ssize_t out_len = bin_len*2 + 2;
+    if (newline) {
         out_len++;
-    ascii_data = _PyBytesWriter_Alloc(&writer, out_len);
-    if (ascii_data == NULL)
+    }
+    PyBytesWriter *writer = PyBytesWriter_Create(out_len);
+    if (writer == NULL) {
         return NULL;
+    }
+    unsigned char *ascii_data = PyBytesWriter_GetData(writer);
 
     for( ; bin_len > 0 ; bin_len--, bin_data++ ) {
         /* Shift the data into our buffer */
@@ -585,7 +589,7 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline)
     if (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;
     Py_ssize_t arglen;
-    PyObject *retval;
-    char* retbuf;
     Py_ssize_t i, j;
     binascii_state *state;
 
@@ -910,10 +912,11 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
         return NULL;
     }
 
-    retval = PyBytes_FromStringAndSize(NULL, (arglen/2));
-    if (!retval)
+    PyBytesWriter *writer = PyBytesWriter_Create(arglen/2);
+    if (writer == NULL) {
         return NULL;
-    retbuf = PyBytes_AS_STRING(retval);
+    }
+    char *retbuf = PyBytesWriter_GetData(writer);
 
     for (i=j=0; i < arglen; i += 2) {
         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) {
             state = get_binascii_state(module);
             if (state == NULL) {
-                return NULL;
+                goto error;
             }
             PyErr_SetString(state->Error,
                             "Non-hexadecimal digit found");
-            goto finally;
+            goto error;
         }
         retbuf[j++] = (top << 4) + bot;
     }
-    return retval;
+    return PyBytesWriter_Finish(writer);
 
-  finally:
-    Py_DECREF(retval);
+error:
+    PyBytesWriter_Discard(writer);
     return NULL;
 }