← index #9957Issue #18144
Related · high · value 3.501
QUERY · ISSUE

signed integer overflow (undefined behavior) in littlefs

openby jepleropened 2022-11-15updated 2024-09-02
bug

While updating #7237 I encountered the following diagnostic from the gcc-10 undefined behavior sanitizer:

--- /home/jepler/src/micropython/tests/results/extmod_vfs_lfs_error.py.exp	2022-11-14 19:56:52.599698807 -0600
+++ /home/jepler/src/micropython/tests/results/extmod_vfs_lfs_error.py.out	2022-11-14 19:56:52.599698807 -0600
@@ -25,4 +25,5 @@
 chdir OSError
 /
 stat OSError
+../../lib/littlefs/lfs2.c:3461:36: runtime error: signed integer overflow: 1073741824 + 1073741824 cannot be represented in type 'int'
 seek OSError

FAILURE /home/jepler/src/micropython/tests/results/extmod_vfs_lfs_error.py

By performing the arithmetic as unsigned, then converting to signed for the comparison, the diagnostic goes away. However, I'm not confident this is an appropriate or complete fix for the problem of seek arithmetic in lfs2_file_rawseek, so I didn't file a PR:

diff --git a/lib/littlefs/lfs2.c b/lib/littlefs/lfs2.c
index a9fcffafd..d3795fec8 100644
--- a/lib/littlefs/lfs2.c
+++ b/lib/littlefs/lfs2.c
@@ -3458,10 +3458,10 @@ static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file,
     if (whence == LFS2_SEEK_SET) {
         npos = off;
     } else if (whence == LFS2_SEEK_CUR) {
-        if ((lfs2_soff_t)file->pos + off < 0) {
+        npos = file->pos + off;
+        if ((lfs2_soff_t)npos < 0) {
             return LFS2_ERR_INVAL;
         } else {
-            npos = file->pos + off;
         }
     } else if (whence == LFS2_SEEK_END) {
         lfs2_soff_t res = lfs2_file_rawsize(lfs2, file) + off;
CANDIDATE · ISSUE

Integer overflow with large ranges

openby jepleropened 2025-09-26updated 2025-09-26
bug

Port, board and/or hardware

unix port, ci unix_sanitize_undefined_build

MicroPython version

MicroPython v1.27.0-preview.208.gadf6319884 on 2025-09-26; linux [GCC 14.2.0] version

Reproduction

Run the following snippet: import sys; print(range(sys.maxsize)[0])

Expected behaviour

No UBsan diagnostics; the number 0 is printed

Observed behaviour

The following diagnostics are produced:

../../py/objrange.c:115:14: runtime error: signed integer overflow: 9223372036854775807 + 1 cannot be represented in type 'long int'
../../py/objrange.c:117:13: runtime error: signed integer overflow: -9223372036854775808 - 1 cannot be represented in type 'long int'

Additional Information

This is related to the cpydiff documented at https://docs.micropython.org/en/latest/genrst/builtin_types.html#range

There are other misbehaving combinations. For instance, here's one with a step that erroneously produces an empty range:

print(range(0, sys.maxsize, sys.maxsize//2)[-1])

but they all seem to stem from signed integer overflows on those two lines (plus line 119 for negative steps)

   113  static mp_int_t range_len(mp_obj_range_t *self) {
   114      // When computing length, need to take into account step!=1 and step
<0.
   115      mp_int_t len = self->stop - self->start + self->step;
   116      if (self->step > 0) {
   117          len -= 1;
   118      } else {
   119          len += 1;
   120      }

Code of Conduct

Yes, I agree

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied