| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -591,24 +591,42 @@ def test_canary_byte(self): | |||
| 591 | 591 | ||
| 592 | 592 | # Test small buffer and large buffer | |
| 593 | 593 | for size in (0, self.SMALL_BUFFER, self.LARGE_BUFFER): | |
| 594 | - with self.subTest(size=size): | ||
| 595 | - code = textwrap.dedent(f""" | ||
| 596 | - from test.support import SuppressCrashReport | ||
| 597 | - import _testcapi | ||
| 598 | - size = {size} | ||
| 599 | - # Add an extra '#' byte to trigger a buffer overflow | ||
| 600 | - data = b'x' * size + b'#' | ||
| 601 | - use_bytearray = {use_bytearray} | ||
| 602 | - writer = _testcapi.PyBytesWriter(size, use_bytearray) | ||
| 603 | - with SuppressCrashReport(): | ||
| 604 | - writer.write(0, data, check=False) | ||
| 605 | - writer.finish() | ||
| 606 | - """) | ||
| 607 | - proc = assert_python_failure('-c', code) | ||
| 608 | - self.assertIn(b'Buffer overflow detected in PyBytesWriter', | ||
| 609 | - proc.err) | ||
| 610 | - self.assertIn(f'at position {size}'.encode(), | ||
| 611 | - proc.err) | ||
| 594 | + for operation in ( | ||
| 595 | + 'writer.get_data()', | ||
| 596 | + 'writer.get_size()', | ||
| 597 | + f'writer.resize({size} * 2)', | ||
| 598 | + f'writer.grow({size})', | ||
| 599 | + 'writer.discard()', | ||
| 600 | + 'writer.finish()', | ||
| 601 | + ): | ||
| 602 | + with self.subTest(size=size, operation=operation): | ||
| 603 | + code = textwrap.dedent(f""" | ||
| 604 | + from test.support import SuppressCrashReport | ||
| 605 | + import os | ||
| 606 | + import _testcapi | ||
| 607 | + size = {size} | ||
| 608 | + # Add an extra '#' byte to trigger a buffer overflow | ||
| 609 | + data = b'x' * size + b'#' | ||
| 610 | + use_bytearray = {use_bytearray} | ||
| 611 | + writer = _testcapi.PyBytesWriter(size, use_bytearray) | ||
| 612 | + with SuppressCrashReport(): | ||
| 613 | + writer.write(0, data, check=False) | ||
| 614 | + try: | ||
| 615 | + {operation} | ||
| 616 | + except: | ||
| 617 | + # Ignore all exceptions | ||
| 618 | + pass | ||
| 619 | + # If we reached this line, the operation didn't | ||
| 620 | + # detect the overflow. Exit immediatetly without | ||
| 621 | + # calling the writer destructor since it can detect | ||
| 622 | + # the overflow. | ||
| 623 | + os._exit(0) | ||
| 624 | + """) | ||
| 625 | + proc = assert_python_failure('-c', code) | ||
| 626 | + self.assertIn(b'Buffer overflow detected in PyBytesWriter', | ||
| 627 | + proc.err) | ||
| 628 | + self.assertIn(f'at position {size}'.encode(), | ||
| 629 | + proc.err) | ||
| 612 | 630 | ||
| 613 | 631 | @unittest.skipUnless(support.Py_DEBUG, 'need debug build') | |
| 614 | 632 | def test_get_data_canary(self): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -315,6 +315,20 @@ writer_finish_with_size(PyObject *self_raw, PyObject *args) | |||
| 315 | 315 | } | |
| 316 | 316 | ||
| 317 | 317 | ||
| 318 | + static PyObject* | ||
| 319 | + writer_discard(PyObject *self_raw, PyObject *Py_UNUSED(args)) | ||
| 320 | + { | ||
| 321 | + WriterObject *self = (WriterObject *)self_raw; | ||
| 322 | + if (writer_check(self) < 0) { | ||
| 323 | + return NULL; | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + PyBytesWriter_Discard(self->writer); | ||
| 327 | + self->writer = NULL; | ||
| 328 | + Py_RETURN_NONE; | ||
| 329 | + } | ||
| 330 | + | ||
| 331 | + | ||
| 318 | 332 | static PyMethodDef writer_methods[] = { | |
| 319 | 333 | {"write", _PyCFunction_CAST(writer_write), METH_VARARGS | METH_KEYWORDS}, | |
| 320 | 334 | {"write_bytes", _PyCFunction_CAST(writer_write_bytes), METH_VARARGS}, | |
@@ -325,6 +339,7 @@ static PyMethodDef writer_methods[] = { | |||
| 325 | 339 | {"get_size", _PyCFunction_CAST(writer_get_size), METH_NOARGS}, | |
| 326 | 340 | {"finish", _PyCFunction_CAST(writer_finish), METH_NOARGS}, | |
| 327 | 341 | {"finish_with_size", _PyCFunction_CAST(writer_finish_with_size), METH_VARARGS}, | |
| 342 | + {"discard", _PyCFunction_CAST(writer_discard), METH_VARARGS}, | ||
| 328 | 343 | {NULL, NULL} /* sentinel */ | |
| 329 | 344 | }; | |
| 330 | 345 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3696,6 +3696,10 @@ byteswriter_resize(PyBytesWriter *writer, Py_ssize_t size, int resize) | |||
| 3696 | 3696 | if (writer->obj != NULL) { | |
| 3697 | 3697 | if (writer->use_bytearray) { | |
| 3698 | 3698 | if (PyByteArray_Resize(writer->obj, size)) { | |
| 3699 | + #ifdef Py_DEBUG | ||
| 3700 | + // bytearray can override the canary byte on error | ||
| 3701 | + byteswriter_write_canary_byte(writer); | ||
| 3702 | + #endif | ||
| 3699 | 3703 | return -1; | |
| 3700 | 3704 | } | |
| 3701 | 3705 | } | |
@@ -3770,6 +3774,11 @@ byteswriter_create(Py_ssize_t size, int use_bytearray) | |||
| 3770 | 3774 | ||
| 3771 | 3775 | if (size >= 1) { | |
| 3772 | 3776 | if (byteswriter_resize(writer, size, 0) < 0) { | |
| 3777 | + #ifdef Py_DEBUG | ||
| 3778 | + // Write the canary byte so byteswriter_check_canary_byte() | ||
| 3779 | + // doesn't fail in PyBytesWriter_Discard() | ||
| 3780 | + byteswriter_write_canary_byte(writer); | ||
| 3781 | + #endif | ||
| 3773 | 3782 | PyBytesWriter_Discard(writer); | |
| 3774 | 3783 | return NULL; | |
| 3775 | 3784 | } | |
@@ -3803,6 +3812,10 @@ PyBytesWriter_Discard(PyBytesWriter *writer) | |||
| 3803 | 3812 | return; | |
| 3804 | 3813 | } | |
| 3805 | 3814 | ||
| 3815 | + #ifdef Py_DEBUG | ||
| 3816 | + byteswriter_check_canary_byte(writer); | ||
| 3817 | + #endif | ||
| 3818 | + | ||
| 3806 | 3819 | Py_XDECREF(writer->obj); | |
| 3807 | 3820 | _Py_FREELIST_FREE(bytes_writers, writer, PyMem_Free); | |
| 3808 | 3821 | } | |
@@ -3875,6 +3888,14 @@ PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size) | |||
| 3875 | 3888 | // The function returns single byte singleton if size equals 1 | |
| 3876 | 3889 | result = PyBytes_FromStringAndSize(writer->small_buffer, size); | |
| 3877 | 3890 | } | |
| 3891 | + | ||
| 3892 | + #ifdef Py_DEBUG | ||
| 3893 | + // Reset the writer, so byteswriter_check_canary_byte() doesn't fail | ||
| 3894 | + // in PyBytesWriter_Discard(). | ||
| 3895 | + writer->size = 0; | ||
| 3896 | + byteswriter_write_canary_byte(writer); | ||
| 3897 | + #endif | ||
| 3898 | + | ||
| 3878 | 3899 | PyBytesWriter_Discard(writer); | |
| 3879 | 3900 | return result; | |
| 3880 | 3901 | ||
@@ -3901,20 +3922,32 @@ PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf) | |||
| 3901 | 3922 | void* | |
| 3902 | 3923 | PyBytesWriter_GetData(PyBytesWriter *writer) | |
| 3903 | 3924 | { | |
| 3925 | + #ifdef Py_DEBUG | ||
| 3926 | + byteswriter_check_canary_byte(writer); | ||
| 3927 | + #endif | ||
| 3928 | + | ||
| 3904 | 3929 | return byteswriter_data(writer); | |
| 3905 | 3930 | } | |
| 3906 | 3931 | ||
| 3907 | 3932 | ||
| 3908 | 3933 | Py_ssize_t | |
| 3909 | 3934 | PyBytesWriter_GetSize(PyBytesWriter *writer) | |
| 3910 | 3935 | { | |
| 3936 | + #ifdef Py_DEBUG | ||
| 3937 | + byteswriter_check_canary_byte(writer); | ||
| 3938 | + #endif | ||
| 3939 | + | ||
| 3911 | 3940 | return _PyBytesWriter_GetSize(writer); | |
| 3912 | 3941 | } | |
| 3913 | 3942 | ||
| 3914 | 3943 | ||
| 3915 | 3944 | int | |
| 3916 | 3945 | PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t new_size) | |
| 3917 | 3946 | { | |
| 3947 | + #ifdef Py_DEBUG | ||
| 3948 | + byteswriter_check_canary_byte(writer); | ||
| 3949 | + #endif | ||
| 3950 | + | ||
| 3918 | 3951 | if (new_size < 0) { | |
| 3919 | 3952 | PyErr_SetString(PyExc_ValueError, "size must be >= 0"); | |
| 3920 | 3953 | return -1; | |
@@ -3950,6 +3983,10 @@ _PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, | |||
| 3950 | 3983 | int | |
| 3951 | 3984 | PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t grow) | |
| 3952 | 3985 | { | |
| 3986 | + #ifdef Py_DEBUG | ||
| 3987 | + byteswriter_check_canary_byte(writer); | ||
| 3988 | + #endif | ||
| 3989 | + | ||
| 3953 | 3990 | if (grow == 0) { | |
| 3954 | 3991 | // Nothing to do | |
| 3955 | 3992 | return 0; | |
@@ -4042,6 +4079,10 @@ PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) | |||
| 4042 | 4079 | static Py_ssize_t | |
| 4043 | 4080 | _PyBytesWriter_ResizeToAllocated(PyBytesWriter *writer) | |
| 4044 | 4081 | { | |
| 4082 | + #ifdef Py_DEBUG | ||
| 4083 | + byteswriter_check_canary_byte(writer); | ||
| 4084 | + #endif | ||
| 4085 | + | ||
| 4045 | 4086 | Py_ssize_t allocated = byteswriter_allocated(writer); | |
| 4046 | 4087 | writer->size = allocated; | |
| 4047 | 4088 | #ifdef Py_DEBUG | |
| Back | FazBrowse Home | New Git URL |
0 commit comments