v923z / micropython-ulab

a numpy-like fast vector module for micropython, circuitpython, and their derivatives
https://micropython-ulab.readthedocs.io/en/latest
MIT License
403 stars 111 forks source link

[BUG] crashes discovered by automated fuzzing #579

Open jepler opened 1 year ago

jepler commented 1 year ago

Hi!

As I did a long time ago for circuitpython, I'm investigating crashes in ulab that can be found by automated techniques such as the aflplusplus fuzzer similar to what I wrote about in my blog: https://emergent.unpythonic.net/01522108310

Mostly this is good for finding parameter validation problems.

Is there interest in me filing bugs for these, either individually or en masse? Most of them probably lead to HardFault type problems when run on hardware, but not necessarily.

Here's a typical one minimized by me:

from ulab import numpy as np
np.arange(2, 12, 0)

Here's one that is not minimized: (the crash occurs on the first sort_complex call with what I think is a zero-length argument)

try:
    from ulab import numpy as np
except:
    import numpy as np

dtypes = (np.uint8, np.int8, np.uint16, np.int16, np.float, np.complex)

for dtype in dtypes:
    print(np.sort_complex(np.array(range(5, 0, 81), dtype=dtype)))

print()
n = 6
a = np.array(range(n, 0, -1)) * 1j
b = np.array([1] * n)
print(np.sort_complex(a + b))

a = np.array(range(n)) * 1j
b = np.array([1] * n)
print(np.sort_complex(a + b))

print()
a = np.array([0, -3j, 1+2j, 1-2j, 2j], dtype=np.complex)
print(np.sort_comp��x(a))

a = np.array([0, 3j, 1-2j, 1+2j, -2j], dtype=np.complex)
print(np.sort_complex(a))
jepler commented 1 year ago

Well this one is weird...!

from ulab import numpy as np   
np.array([range(0),range(2000)])
t(n(i))

results in the exception NotImplementedError: opcode. Other variants would cause segfaults and assertion failures but I think this is the minimum to cause an obvious misbehavior that probably indicates memory corruption.

v923z commented 1 year ago

Mostly this is good for finding parameter validation problems.

Is there interest in me filing bugs for these, either individually or en masse? Most of them probably lead to HardFault type problems when run on hardware, but not necessarily.

I think issues, especially, if they result in hard faults, should be fixed, no matter how they are found. So, yes, please! I have, however, two comments.

  1. Since argument validation is most probably going to happen on a case-by-case basis, we can't just craft a universal validator function, and call it everything. The upshot is that the firmware will be larger, and, to quote a classic "Code space is always at a premium", so we should consider, whether weeding out edge cases is worth bytes that we've got to pay for it.
  2. If possible, I would like a new ticket for each issue. Otherwise, I feel that we might lose track. Also, smaller bugs are easier to fix, and I see value of rolling out a fix as soon as possible, without having wait till everything is sorted out.

Having said all these, I'm flexible, and if you don't agree with my comments above, I'm willing to change my mind. You (meaning circuitpython and its users) use ulab much more frequently than myself, so if it doesn't live up to your expectations, then my opinion shouldn't matter too much.

Here's a typical one minimized by me:

from ulab import numpy as np
np.arange(2, 12, 0)

arange is a notorious one, given that the order of arguments changes, depending on how many you have: https://numpy.org/doc/stable/reference/generated/numpy.arange.html. But this issue is a bad one, so I'll just open a ticket. Thanks for bringing it up.

https://github.com/v923z/micropython-ulab/issues/580

Here's one that is not minimized: (the crash occurs on the first sort_complex call with what I think is a zero-length argument)

I've opened an issue for this one, too: https://github.com/v923z/micropython-ulab/issues/581

v923z commented 1 year ago

Well this one is weird...!

from ulab import numpy as np   
np.array([range(0),range(2000)])
t(n(i))

results in the exception NotImplementedError: opcode. Other variants would cause segfaults and assertion failures but I think this is the minimum to cause an obvious misbehavior that probably indicates memory corruption.

I'm not quite sure I understand what the problem is. What is t()?

But numpy actually results in a deprecation warning:

>>> import numpy as np
>>> np.array([range(0), range(2)])
<stdin>:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
array([range(0, 0), range(0, 2)], dtype=object)

so, perhaps, the array method has to be updated.