@@ -151,9 +151,9 @@ writer_write_bytes(PyObject *self_raw, PyObject *args)
151151 return NULL ;
152152 }
153153
154- char * bytes ;
155- Py_ssize_t size ;
156- if (!PyArg_ParseTuple (args , "yn " , & bytes , & size )) {
154+ const char * bytes ;
155+ Py_ssize_t unused_size , size ;
156+ if (!PyArg_ParseTuple (args , "y#n " , & bytes , & unused_size , & size )) {
157157 return NULL ;
158158 }
159159
@@ -383,12 +383,107 @@ pybyteswriter_small_buffer_size(void)
383383}
384384
385385
386+ // Test the "Pointer" API of PyBytesWriter
387+ static PyObject *
388+ test_byteswriter_ptr (PyObject * Py_UNUSED (module ), PyObject * Py_UNUSED (args ))
389+ {
390+ // Test PyBytesWriter_FinishWithPointer(): create the string "abc"
391+ PyBytesWriter * writer = PyBytesWriter_Create (3 );
392+ if (writer == NULL ) {
393+ return NULL ;
394+ }
395+ char * str = PyBytesWriter_GetData (writer );
396+ memcpy (str , "abc" , 3 );
397+ str += 3 ;
398+ PyObject * result = PyBytesWriter_FinishWithPointer (writer , str );
399+ if (result == NULL ) {
400+ return NULL ;
401+ }
402+ assert (PyBytes_GET_SIZE (result ) == 3 );
403+ assert (memcmp (PyBytes_AS_STRING (result ), "abc" , 3 ) == 0 );
404+ Py_DECREF (result );
405+
406+ // Test PyBytesWriter_GrowAndUpdatePointer().
407+ // Start by using the small buffer, and then resize to use a bytes object.
408+ writer = PyBytesWriter_Create (0 );
409+ if (writer == NULL ) {
410+ return NULL ;
411+ }
412+ str = PyBytesWriter_GetData (writer );
413+
414+ str = PyBytesWriter_GrowAndUpdatePointer (writer , 100 , str );
415+ if (str == NULL ) {
416+ PyBytesWriter_Discard (writer );
417+ return NULL ;
418+ }
419+ memset (str , 'x' , 100 );
420+ str += 100 ;
421+
422+ // make sure that the test switchs to a bytes object
423+ assert ((100 + 200 ) > pybyteswriter_small_buffer_size ());
424+ char * old_str = str ;
425+ str = PyBytesWriter_GrowAndUpdatePointer (writer , 200 , str );
426+ if (str == NULL ) {
427+ PyBytesWriter_Discard (writer );
428+ return NULL ;
429+ }
430+ // make sure that we moved from the small buffer to a bytes object
431+ assert (str != old_str );
432+ memset (str , 'y' , 200 );
433+ str += 200 ;
434+
435+ result = PyBytesWriter_FinishWithPointer (writer , str );
436+ if (result == NULL ) {
437+ return NULL ;
438+ }
439+ assert (PyBytes_GET_SIZE (result ) == 300 );
440+ str = PyBytes_AS_STRING (result );
441+ for (Py_ssize_t i = 0 ; i < 100 ; i ++ ) {
442+ assert (str [i ] == 'x' );
443+ }
444+ for (Py_ssize_t i = 0 ; i < 200 ; i ++ ) {
445+ assert (str [100 + i ] == 'y' );
446+ }
447+ Py_DECREF (result );
448+
449+ // Check that PyBytesWriter_FinishWithPointer() rejects pointer
450+ // after the buffer end (create a string larger than the allocated size)
451+ writer = PyBytesWriter_Create (3 );
452+ if (writer == NULL ) {
453+ return NULL ;
454+ }
455+ str = PyBytesWriter_GetData (writer );
456+ memcpy (str , "abc" , 3 );
457+ str += 4 ; // off-by-one bug on purpose
458+ result = PyBytesWriter_FinishWithPointer (writer , str );
459+ assert (result == NULL );
460+ assert (PyErr_ExceptionMatches (PyExc_ValueError ));
461+ PyErr_Clear ();
462+
463+ // Check that PyBytesWriter_FinishWithPointer() rejects pointer
464+ // before the buffer start (negative size)
465+ writer = PyBytesWriter_Create (3 );
466+ if (writer == NULL ) {
467+ return NULL ;
468+ }
469+ str = PyBytesWriter_GetData (writer );
470+ str -- ; // bug on purpose: go before the buffer start
471+ result = PyBytesWriter_FinishWithPointer (writer , str );
472+ assert (result == NULL );
473+ assert (PyErr_ExceptionMatches (PyExc_ValueError ));
474+ PyErr_Clear ();
475+
476+ Py_RETURN_NONE ;
477+ }
478+
479+
386480static PyMethodDef test_methods [] = {
387481 {"bytes_resize" , bytes_resize , METH_VARARGS },
388482 {"bytes_join" , bytes_join , METH_VARARGS },
389483 {"byteswriter_abc" , byteswriter_abc , METH_NOARGS },
390484 {"byteswriter_resize" , byteswriter_resize , METH_NOARGS },
391485 {"byteswriter_highlevel" , byteswriter_highlevel , METH_NOARGS },
486+ {"test_byteswriter_ptr" , test_byteswriter_ptr , METH_NOARGS },
392487 {NULL },
393488};
394489
0 commit comments