Skip to content

Commit de3b052

Browse files
committed
Buffer objects would return the read or write buffer for a wrapped object when
the char buffer was requested. Now it actually returns the char buffer if available or raises a TypeError if it isn't (as is raised for the other buffer types if they are not present but requested). Not a backport candidate since it does change semantics of the buffer object (although it could be argued this is enough of a bug to bother backporting).
1 parent 6ee7d01 commit de3b052

4 files changed

Lines changed: 85 additions & 22 deletions

File tree

‎Lib/test/test_types.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,10 @@ class C: pass
276276
try: a[0:1] = 'g'
277277
except TypeError: pass
278278
else: raise TestFailed, "buffer slice assignment should raise TypeError"
279+
280+
# array.array() returns an object that does not implement a char buffer,
281+
# something which int() uses for conversion.
282+
import array
283+
try: int(buffer(array.array('c')))
284+
except TypeError :pass
285+
else: raise TestFailed, "char buffer (at C level) not working"

‎Misc/NEWS‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ What's New in Python 2.5 beta 1?
1212
Core and builtins
1313
-----------------
1414

15+
- Buffer objects, at the C level, never used the char buffer
16+
implementation even when the char buffer for the wrapped object was
17+
explicitly requested (originally returned the read or write buffer).
18+
Now a TypeError is raised if the char buffer is not present but is
19+
requested.
20+
1521
- Patch #1346214: Statements like "if 0: suite" are now again optimized
1622
away like they were in Python 2.4.
1723

‎Modules/arraymodule.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,7 @@ static PyBufferProcs array_as_buffer = {
17871787
(readbufferproc)array_buffer_getreadbuf,
17881788
(writebufferproc)array_buffer_getwritebuf,
17891789
(segcountproc)array_buffer_getsegcount,
1790+
NULL,
17901791
};
17911792

17921793
static PyObject *

‎Objects/bufferobject.c‎

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,16 @@ typedef struct {
1515
} PyBufferObject;
1616

1717

18+
enum buffer_t {
19+
READBUFFER,
20+
WRITEBUFFER,
21+
CHARBUFFER,
22+
ANY_BUFFER,
23+
};
24+
1825
static int
19-
get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size)
26+
get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size,
27+
enum buffer_t buffer_type)
2028
{
2129
if (self->b_base == NULL) {
2230
assert (ptr != NULL);
@@ -32,10 +40,42 @@ get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size)
3240
"single-segment buffer object expected");
3341
return 0;
3442
}
35-
if (self->b_readonly)
36-
proc = bp->bf_getreadbuffer;
37-
else
38-
proc = (readbufferproc)bp->bf_getwritebuffer;
43+
if ((buffer_type == READBUFFER) ||
44+
((buffer_type == ANY_BUFFER) && self->b_readonly))
45+
proc = bp->bf_getreadbuffer;
46+
else if ((buffer_type == WRITEBUFFER) ||
47+
(buffer_type == ANY_BUFFER))
48+
proc = (readbufferproc)bp->bf_getwritebuffer;
49+
else if (buffer_type == CHARBUFFER) {
50+
if (!PyType_HasFeature(self->ob_type,
51+
Py_TPFLAGS_HAVE_GETCHARBUFFER)) {
52+
PyErr_SetString(PyExc_TypeError,
53+
"Py_TPFLAGS_HAVE_GETCHARBUFFER needed");
54+
return 0;
55+
}
56+
proc = (readbufferproc)bp->bf_getcharbuffer;
57+
}
58+
if (!proc) {
59+
char *buffer_type_name;
60+
switch (buffer_type) {
61+
case READBUFFER:
62+
buffer_type_name = "read";
63+
break;
64+
case WRITEBUFFER:
65+
buffer_type_name = "write";
66+
break;
67+
case CHARBUFFER:
68+
buffer_type_name = "char";
69+
break;
70+
default:
71+
buffer_type_name = "no";
72+
break;
73+
}
74+
PyErr_Format(PyExc_TypeError,
75+
"%s buffer type not available",
76+
buffer_type_name);
77+
return 0;
78+
}
3979
if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
4080
return 0;
4181
/* apply constraints to the start/end */
@@ -224,9 +264,9 @@ buffer_compare(PyBufferObject *self, PyBufferObject *other)
224264
Py_ssize_t len_self, len_other, min_len;
225265
int cmp;
226266

227-
if (!get_buf(self, &p1, &len_self))
267+
if (!get_buf(self, &p1, &len_self, ANY_BUFFER))
228268
return -1;
229-
if (!get_buf(other, &p2, &len_other))
269+
if (!get_buf(other, &p2, &len_other, ANY_BUFFER))
230270
return -1;
231271
min_len = (len_self < len_other) ? len_self : len_other;
232272
if (min_len > 0) {
@@ -284,7 +324,7 @@ buffer_hash(PyBufferObject *self)
284324
return -1;
285325
}
286326

287-
if (!get_buf(self, &ptr, &size))
327+
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
288328
return -1;
289329
p = (unsigned char *) ptr;
290330
len = size;
@@ -303,7 +343,7 @@ buffer_str(PyBufferObject *self)
303343
{
304344
void *ptr;
305345
Py_ssize_t size;
306-
if (!get_buf(self, &ptr, &size))
346+
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
307347
return NULL;
308348
return PyString_FromStringAndSize((const char *)ptr, size);
309349
}
@@ -315,7 +355,7 @@ buffer_length(PyBufferObject *self)
315355
{
316356
void *ptr;
317357
Py_ssize_t size;
318-
if (!get_buf(self, &ptr, &size))
358+
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
319359
return -1;
320360
return size;
321361
}
@@ -344,7 +384,7 @@ buffer_concat(PyBufferObject *self, PyObject *other)
344384
return NULL;
345385
}
346386

347-
if (!get_buf(self, &ptr1, &size))
387+
if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
348388
return NULL;
349389

350390
/* optimize special case */
@@ -380,7 +420,7 @@ buffer_repeat(PyBufferObject *self, Py_ssize_t count)
380420

381421
if ( count < 0 )
382422
count = 0;
383-
if (!get_buf(self, &ptr, &size))
423+
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
384424
return NULL;
385425
ob = PyString_FromStringAndSize(NULL, size * count);
386426
if ( ob == NULL )
@@ -404,7 +444,7 @@ buffer_item(PyBufferObject *self, Py_ssize_t idx)
404444
{
405445
void *ptr;
406446
Py_ssize_t size;
407-
if (!get_buf(self, &ptr, &size))
447+
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
408448
return NULL;
409449
if ( idx < 0 || idx >= size ) {
410450
PyErr_SetString(PyExc_IndexError, "buffer index out of range");
@@ -418,7 +458,7 @@ buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
418458
{
419459
void *ptr;
420460
Py_ssize_t size;
421-
if (!get_buf(self, &ptr, &size))
461+
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
422462
return NULL;
423463
if ( left < 0 )
424464
left = 0;
@@ -446,7 +486,7 @@ buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
446486
return -1;
447487
}
448488

449-
if (!get_buf(self, &ptr1, &size))
489+
if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
450490
return -1;
451491

452492
if (idx < 0 || idx >= size) {
@@ -513,7 +553,7 @@ buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObje
513553
"single-segment buffer object expected");
514554
return -1;
515555
}
516-
if (!get_buf(self, &ptr1, &size))
556+
if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
517557
return -1;
518558
if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
519559
return -1;
@@ -552,28 +592,38 @@ buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
552592
"accessing non-existent buffer segment");
553593
return -1;
554594
}
555-
if (!get_buf(self, pp, &size))
595+
if (!get_buf(self, pp, &size, READBUFFER))
556596
return -1;
557597
return size;
558598
}
559599

560600
static Py_ssize_t
561601
buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
562602
{
603+
Py_ssize_t size;
604+
563605
if ( self->b_readonly )
564606
{
565607
PyErr_SetString(PyExc_TypeError, "buffer is read-only");
566608
return -1;
567609
}
568-
return buffer_getreadbuf(self, idx, pp);
610+
611+
if ( idx != 0 ) {
612+
PyErr_SetString(PyExc_SystemError,
613+
"accessing non-existent buffer segment");
614+
return -1;
615+
}
616+
if (!get_buf(self, pp, &size, WRITEBUFFER))
617+
return -1;
618+
return size;
569619
}
570620

571621
static Py_ssize_t
572622
buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
573623
{
574624
void *ptr;
575625
Py_ssize_t size;
576-
if (!get_buf(self, &ptr, &size))
626+
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
577627
return -1;
578628
if (lenp)
579629
*lenp = size;
@@ -590,13 +640,12 @@ buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
590640
"accessing non-existent buffer segment");
591641
return -1;
592642
}
593-
if (!get_buf(self, &ptr, &size))
643+
if (!get_buf(self, &ptr, &size, CHARBUFFER))
594644
return -1;
595645
*pp = (const char *)ptr;
596646
return size;
597647
}
598648

599-
600649
static PySequenceMethods buffer_as_sequence = {
601650
(lenfunc)buffer_length, /*sq_length*/
602651
(binaryfunc)buffer_concat, /*sq_concat*/
@@ -635,7 +684,7 @@ PyTypeObject PyBuffer_Type = {
635684
PyObject_GenericGetAttr, /* tp_getattro */
636685
0, /* tp_setattro */
637686
&buffer_as_buffer, /* tp_as_buffer */
638-
Py_TPFLAGS_DEFAULT, /* tp_flags */
687+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */
639688
buffer_doc, /* tp_doc */
640689
0, /* tp_traverse */
641690
0, /* tp_clear */

0 commit comments

Comments
 (0)