Skip to content

Commit d1574de

Browse files
corranwebsterdpgeorge
authored andcommitted
extmod/modframebuf: Fix FrameBuffer size check for stride corner-cases.
This is a fix for issue micropython#15944, and handles corner cases in the FrameBuffer code when using stride values where the last line's stride may extend past the end of the underlying buffer. This commit includes extra tests for these corner cases. For example a GS8 format FrameBuffer with a width of 8, height of 2 and stride of 10 should be able to fit into a buffer of size 18 (10 bytes for the first horizontal line, and 8 bytes for the second -- the full 10 bytes are not needed). Similarly a 1 by 9 FrameBuffer in MONO_VLSB format with a stride of 10 should be able to fit into a buffer of length 11 (10 bytes for the first 8 lines, and then one byte for the 9th line. Being able to do this is particularly important when cropping the corner of an existing FrameBuffer, either to copy a sprite or to clip drawing. Signed-off-by: Corran Webster <[email protected]>
1 parent 7ed480f commit d1574de

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

extmod/modframebuf.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,23 +282,29 @@ static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size
282282
mp_raise_ValueError(NULL);
283283
}
284284

285-
size_t height_required = height;
286285
size_t bpp = 1;
286+
size_t height_required = height;
287+
size_t width_required = width;
288+
size_t strides_required = height - 1;
287289

288290
switch (format) {
289291
case FRAMEBUF_MVLSB:
290292
height_required = (height + 7) & ~7;
293+
strides_required = height_required - 8;
291294
break;
292295
case FRAMEBUF_MHLSB:
293296
case FRAMEBUF_MHMSB:
294297
stride = (stride + 7) & ~7;
298+
width_required = (width + 7) & ~7;
295299
break;
296300
case FRAMEBUF_GS2_HMSB:
297301
stride = (stride + 3) & ~3;
302+
width_required = (width + 3) & ~3;
298303
bpp = 2;
299304
break;
300305
case FRAMEBUF_GS4_HMSB:
301306
stride = (stride + 1) & ~1;
307+
width_required = (width + 1) & ~1;
302308
bpp = 4;
303309
break;
304310
case FRAMEBUF_GS8:
@@ -314,7 +320,7 @@ static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size
314320
mp_buffer_info_t bufinfo;
315321
mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE);
316322

317-
if (height_required * stride * bpp / 8 > bufinfo.len) {
323+
if ((strides_required * stride + (height_required - strides_required) * width_required) * bpp / 8 > bufinfo.len) {
318324
mp_raise_ValueError(NULL);
319325
}
320326

tests/extmod/framebuf_bounds.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,25 @@ def test_constructor(*args):
2121
test_constructor(bytearray(20), 10, 10, framebuf.MONO_HLSB, 10)
2222
test_constructor(bytearray(20), 10, 10, framebuf.MONO_HLSB, 9)
2323
test_constructor(bytearray(20), 10, 10, framebuf.MONO_HLSB, -1)
24+
test_constructor(bytearray(20), 10, 10, framebuf.MONO_HLSB, 16)
25+
test_constructor(bytearray(20), 10, 10, framebuf.MONO_HLSB, 17)
26+
test_constructor(bytearray(19), 8, 10, framebuf.MONO_HLSB, 16)
27+
test_constructor(bytearray(18), 8, 10, framebuf.MONO_HLSB, 9)
28+
test_constructor(bytearray(19), 8, 10, framebuf.MONO_HLSB, 16)
2429

2530
print(framebuf.MONO_VLSB)
2631
test_constructor(bytearray(8), 8, 1, framebuf.MONO_VLSB)
2732
test_constructor(bytearray(7), 8, 1, framebuf.MONO_VLSB)
2833
test_constructor(bytearray(8), 8, 8, framebuf.MONO_VLSB)
34+
test_constructor(bytearray(1), 1, 8, framebuf.MONO_VLSB)
35+
test_constructor(bytearray(1), 1, 9, framebuf.MONO_VLSB)
36+
test_constructor(bytearray(2), 1, 9, framebuf.MONO_VLSB)
37+
test_constructor(bytearray(1), 1, 8, framebuf.MONO_VLSB, 10)
38+
test_constructor(bytearray(8), 8, 8, framebuf.MONO_VLSB, 10)
39+
test_constructor(bytearray(8), 8, 8, framebuf.MONO_VLSB, 7)
40+
test_constructor(bytearray(11), 1, 9, framebuf.MONO_VLSB, 10)
41+
test_constructor(bytearray(10), 1, 9, framebuf.MONO_VLSB, 10)
42+
test_constructor(bytearray(11), 1, 16, framebuf.MONO_VLSB, 10)
2943

3044
for f in (framebuf.MONO_HLSB, framebuf.MONO_HMSB):
3145
print(f)
@@ -40,21 +54,37 @@ def test_constructor(*args):
4054
test_constructor(bytearray(15), 5, 8, framebuf.GS2_HMSB)
4155
test_constructor(bytearray(16), 5, 8, framebuf.GS2_HMSB)
4256
test_constructor(bytearray(9), 4, 9, framebuf.GS2_HMSB)
57+
test_constructor(bytearray(2), 7, 1, framebuf.GS2_HMSB, 9)
58+
test_constructor(bytearray(4), 7, 2, framebuf.GS2_HMSB, 9)
59+
test_constructor(bytearray(5), 7, 2, framebuf.GS2_HMSB, 9)
4360

4461
print(framebuf.GS4_HMSB)
4562
test_constructor(bytearray(8), 2, 8, framebuf.GS4_HMSB)
4663
test_constructor(bytearray(15), 3, 8, framebuf.GS4_HMSB)
4764
test_constructor(bytearray(16), 3, 8, framebuf.GS4_HMSB)
4865
test_constructor(bytearray(9), 2, 9, framebuf.GS4_HMSB)
66+
test_constructor(bytearray(4), 7, 1, framebuf.GS4_HMSB, 9)
67+
test_constructor(bytearray(8), 7, 2, framebuf.GS4_HMSB, 9)
68+
test_constructor(bytearray(9), 7, 2, framebuf.GS4_HMSB, 9)
4969

5070
print(framebuf.GS8)
5171
test_constructor(bytearray(63), 8, 8, framebuf.GS8)
5272
test_constructor(bytearray(64), 8, 8, framebuf.GS8)
5373
test_constructor(bytearray(64), 9, 8, framebuf.GS8)
5474
test_constructor(bytearray(64), 8, 9, framebuf.GS8)
75+
test_constructor(bytearray(64), 4, 8, framebuf.GS8, 8)
76+
test_constructor(bytearray(64), 4, 8, framebuf.GS8, 9)
77+
test_constructor(bytearray(8), 8, 1, framebuf.GS8, 10)
78+
test_constructor(bytearray(17), 8, 2, framebuf.GS8, 10)
79+
test_constructor(bytearray(18), 8, 2, framebuf.GS8, 10)
5580

5681
print(framebuf.RGB565)
5782
test_constructor(bytearray(127), 8, 8, framebuf.RGB565)
5883
test_constructor(bytearray(128), 8, 8, framebuf.RGB565)
5984
test_constructor(bytearray(128), 9, 8, framebuf.RGB565)
6085
test_constructor(bytearray(128), 8, 9, framebuf.RGB565)
86+
test_constructor(bytearray(128), 4, 8, framebuf.RGB565, 8)
87+
test_constructor(bytearray(128), 4, 8, framebuf.RGB565, 9)
88+
test_constructor(bytearray(16), 8, 1, framebuf.RGB565, 10)
89+
test_constructor(bytearray(34), 8, 2, framebuf.RGB565, 10)
90+
test_constructor(bytearray(36), 8, 2, framebuf.RGB565, 10)

tests/extmod/framebuf_bounds.py.exp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,24 @@ Valid
66
Valid
77
ValueError
88
ValueError
9+
Valid
10+
ValueError
11+
Valid
12+
ValueError
13+
Valid
914
0
1015
Valid
1116
ValueError
1217
Valid
18+
Valid
19+
ValueError
20+
Valid
21+
Valid
22+
Valid
23+
ValueError
24+
Valid
25+
ValueError
26+
Valid
1327
3
1428
Valid
1529
ValueError
@@ -27,18 +41,34 @@ Valid
2741
ValueError
2842
Valid
2943
Valid
44+
Valid
45+
ValueError
46+
Valid
3047
2
3148
Valid
3249
ValueError
3350
Valid
3451
Valid
52+
Valid
53+
ValueError
54+
Valid
3555
6
3656
ValueError
3757
Valid
3858
ValueError
3959
ValueError
60+
Valid
61+
ValueError
62+
Valid
63+
ValueError
64+
Valid
4065
1
4166
ValueError
4267
Valid
4368
ValueError
4469
ValueError
70+
Valid
71+
ValueError
72+
Valid
73+
ValueError
74+
Valid

0 commit comments

Comments
 (0)