8000 Add overflow checks for int to bytes conversions · projectgus/micropython@095c844 · GitHub
[go: up one dir, main page]

Skip to content

Commit 095c844

Browse files
author
Matt Wozniski
committed
Add overflow checks for int to bytes conversions
For both small and long integers, raise an exception if calling struct.pack, adding an element to an array.array, or formatting an int with int.to_bytes would overflow the requested size.
1 parent e041df7 commit 095c844

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

py/binary.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,15 +304,18 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
304304
break;
305305
}
306306
#endif
307-
default:
307+
default: {
308+
bool signed_type = is_signed(val_type);
308309
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
309310
if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
311+
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
310312
mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
311313
return;
312314
} else
313315
#endif
314316
{
315317
val = mp_obj_get_int(val_in);
318+
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
316319
// zero/sign extend if needed
317320
if (BYTES_PER_WORD < 8 && size > sizeof(val)) {
318321
int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00;
@@ -322,6 +325,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
322325
}
323326
}
324327
}
328+
}
325329
}
326330

327331
mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
@@ -343,16 +347,22 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v
343347
((mp_obj_t*)p)[index] = val_in;
344348
break;
345349
#endif
346-
default:
350+
default: {
351+
size_t size = mp_binary_get_size('@', typecode, NULL);
352+
bool signed_type = is_signed(typecode);
353+
347354
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
348355
if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
349-
size_t size = mp_binary_get_size('@', typecode, NULL);
356+
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
350357
mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
351358
size, (uint8_t*)p + index * size);
352359
return;
353360
}
354361
#endif
355-
mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
362+
mp_int_t val = mp_obj_get_int(val_in);
363+
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
364+
mp_binary_set_val_array_from_int(typecode, p, index, val);
365+
}
356366
}
357367
}
358368

py/objint.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,49 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
300300
return b;
301301
}
302302

303+
void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed)
304+
{
305+
if (is_signed) {
306+
// edge = 1 << (nbytes * 8 - 1)
307+
mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT,
308+
mp_obj_new_int(1),
309+
mp_obj_new_int(nbytes * 8 - 1));
310+
311+
// if self >= edge, we don't fit
312+
if (mp_binary_op(MP_BINARY_OP_MORE_EQUAL, self_in, edge) == mp_const_true) {
313+
goto raise;
314+
}
315+
316+
// edge = -edge
317+
edge = mp_unary_op(MP_UNARY_OP_NEGATIVE, edge);
318+
319+
// if self < edge, we don't fit
320+
if (mp_binary_op(MP_BINARY_OP_LESS, self_in, edge) == mp_const_true) {
321+
goto raise;
322+
}
323+
} else {
324+
if (mp_obj_int_sign(self_in) < 0) {
325+
// Negative numbers never fit in an unsigned value
326+
goto raise;
327+
}
328+
329+
// edge = 1 << (nbytes * 8)
330+
mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT,
331+
mp_obj_new_int(1),
332+
mp_obj_new_int(nbytes * 8));
333+
334+
// if self >= edge, we don't fit
335+
if (mp_binary_op(MP_BINARY_OP_MORE_EQUAL, self_in, edge) == mp_const_true) {
336+
goto raise;
337+
}
338+
}
339+
340+
return;
341+
342+
raise:
343+
mp_raise_ValueError_varg(translate("value would overflow a %d byte buffer"), nbytes);
344+
}
345+
303346
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
304347

305348
int mp_obj_int_sign(mp_obj_t self_in) {
@@ -435,6 +478,8 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {
435478
byte *data = (byte*)vstr.buf;
436479
memset(data, 0, len);
437480

481+
mp_obj_int_buffer_overflow_check(args[0], len, false);
482+
438483
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
439484
if (!MP_OBJ_IS_SMALL_INT(args[0])) {
440485
mp_obj_int_to_bytes_impl(args[0], big_endian, len, data);

py/objint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
5353
int base, const char *prefix, char base_char, char comma);
5454
char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
5555
int base, const char *prefix, char base_char, char comma);
56+
void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed);
5657
mp_int_t mp_obj_int_hash(mp_obj_t self_in);
5758
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf);
5859
void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf);

0 commit comments

Comments
 (0)
0