Skip to content

ports: Raise an error at a negative argument of os.urandom(). - #18833

Merged
dpgeorge merged 3 commits into
micropython:masterfrom
robert-hh:ports_urandom
Feb 24, 2026
Merged

dpgeorge merged 3 commits into
micropython:masterfrom
robert-hh:ports_urandom

Conversation

@robert-hh

Copy link
Copy Markdown
Contributor

Summary

Raise an error at a negative argument of os.urandom().

Testing

Tested for the cc3200, esp32, esp8266, mimxrt, nrf, rp2, samd, stm32 and unix ports. Compiled for the alif and the renesas port but not tested lacking suitable boards.

Argument values -1, 0, 3

Trade-offs and Alternatives

The PR repeats the same few lines of code for each port. That looks not nice. I tried to factor out the common code part if mp_os_urandom(), but that fails for quite a few build vaiants. To be tested further, if needed.

@github-actions

github-actions Bot commented Feb 17, 2026 •

Copy link
Copy Markdown

Code size report:

Reference:  docs/develop/writingtests: Document parameters of run_test.py. [fdb7c0f]
Comparison: tests/extmod/os_urandom.py: Add test for os.urandom. [merge of 6dbabc9]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:   +32 +0.008% PYBV10
      esp32:   +20 +0.001% ESP32_GENERIC
     mimxrt:   +24 +0.006% TEENSY40
        rp2:   +24 +0.003% RPI_PICO_W
       samd:   +24 +0.009% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@codecov

codecov Bot commented Feb 17, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.42%. Comparing base (fdb7c0f) to head (6dbabc9).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #18833      +/-   ##
==========================================
- Coverage   98.42%   98.42%   -0.01%     
==========================================
  Files         174      174              
  Lines       22334    22328       -6     
==========================================
- Hits        21983    21977       -6     
  Misses        351      351              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread ports/mimxrt/modos.c
vstr_init_len(&vstr, n);

trng_start();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this line removed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because trng_start() is called again in trng_random_data(). So it was obsolete.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, but it seems like an unrelated change to the subject of the commit

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is. Just a windfall benefit.

@Josverl

Josverl commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

@robert-hh ,
I notice a test missing for the new error,
I also wonder if it would not be sufficient to raise just a ValueError and omit the text. That should save some bytes.
Or the error should be matched to CPython's .

# 3.11.9
>>> os.urandom(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: negative argument not allowed

@projectgus projectgus linked an issue Feb 17, 2026 that may be closed by this pull request
@projectgus
projectgus self-requested a review February 17, 2026 23:52
@robert-hh

robert-hh commented Feb 18, 2026 •

Copy link
Copy Markdown
Contributor Author

I had considered both just having ValueError for small flash devices or using the CPython error message and ended with the actual text as compromise for lower complexity.

@robert-hh

Copy link
Copy Markdown
Contributor Author

By the way: I did not change the Windows port because I could not spot the source files. The ports/windows directory does not have many of these. I used to build Windows versions > 7 years ago, and it seems I lost track for that port.

@Josverl

Josverl commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

It does have the same issue in 1.27 , but afaikt it uses the code from the Unix port for this, so your fix should work.
Adding a test to CI will help verify. I'll try to find time to test.

@dpgeorge

Copy link
Copy Markdown
Member

The PR repeats the same few lines of code for each port. That looks not nice. I tried to factor out the common code part if mp_os_urandom(),

I think we should do that first. All existing port-specific implementations look like this:

static mp_obj_t mp_os_urandom(mp_obj_t num) {
    mp_int_t n = mp_obj_get_int(num);
    vstr_t vstr;
    vstr_init_len(&vstr, n);
    // port specific code to fill vstr.buf
    return mp_obj_new_bytes_from_vstr(&vstr);
}
static MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom);

so could factor that code into extmod/modos.c as something like:

static mp_obj_t mp_os_urandom(mp_obj_t num) {
    mp_int_t n = mp_obj_get_int(num);
    vstr_t vstr;
    vstr_init_len(&vstr, n);
    mp_os_urandom_bytes(n, vstr.buf);
    return mp_obj_new_bytes_from_vstr(&vstr);
}
static MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom);

and then each port defines void mp_os_urandom_bytes(size_t n, uint8_t *buf) in its modos.c.

@robert-hh would you like to do that?

@dpgeorge dpgeorge added ports Relates to multiple ports, or a new/proposed port extmod Relates to extmod/ directory in source labels Feb 20, 2026
@projectgus

Copy link
Copy Markdown
Contributor

and then each port defines void mp_os_urandom_bytes(size_t n, uint8_t *buf) in its modos.c.

If we do this then we can also probably refactor the other places in each port which fill a buffer with random bytes (i.e. similar to the changes in #18834) to call that single helper function, maybe save a little more code size.

@dpgeorge

Copy link
Copy Markdown
Member

If we do this then we can also probably refactor the other places in each port which fill a buffer with random bytes

Yes, good idea. In that case maybe copy what the unix port already has: mp_hal_get_random().

@robert-hh

Copy link
Copy Markdown
Contributor Author

@robert-hh would you like to do that?

@dpgeorge Sure. I had already prepared it, will call that function providing the raw values mp_hal_get_random() and put it into mphalport.c.

@robert-hh

Copy link
Copy Markdown
Contributor Author

@dpgeorge I hav a question about an implementation detail, before changing 11 ports. The unix port defines void mp_hal_get_random(size_t n, void *buf);. Shouldn't it be better void mp_hal_get_random(size_t n, uint8_t *buf);, because that's what the ports do in their implementation of os.urandom().

@dpgeorge

Copy link
Copy Markdown
Member

Shouldn't it be better void mp_hal_get_random(size_t n, uint8_t *buf)

Yes, change the unix port to uint8_t *buf looks better (and I don't see any downsides of that change).

@robert-hh
robert-hh force-pushed the ports_urandom branch 2 times, most recently from ff8b597 to bdea95a Compare February 20, 2026 16:13
@robert-hh

robert-hh commented Feb 20, 2026 •

Copy link
Copy Markdown
Contributor Author

@dpgeorge os.orandom() is now factored out. It ended up with quite a few changed files, but the changes are similar for all ports. The actual random numbers are provided by mp_hal_get_random() of each port. The respective implementation for the ports is moved to mphalport.x or equivalent, except for MIMXRT and SAMD, because theses have more than on instance of mp_hal_get_random() calling another function. That is better kept in a single place.

The PR still has two commits for visibility during the review, but the first one should be squashed. Using mp_hal_get_random() at other places in the code is not yet included. That can be done when the actual state is clean.

@robert-hh
robert-hh force-pushed the ports_urandom branch 4 times, most recently from 5f4c8e0 to e7c646b Compare February 21, 2026 16:33

@dpgeorge dpgeorge left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good if the two commits could be swapped around: first commit does the refactoring, second commit adds the <0 check.

Comment thread extmod/modos.c Outdated
Comment thread extmod/modos.c Outdated
@robert-hh
robert-hh force-pushed the ports_urandom branch 2 times, most recently from 595fc21 to 52e9f8a Compare February 22, 2026 08:25
@robert-hh

Copy link
Copy Markdown
Contributor Author

The suggested changes are made.

I spotted at least one typical place to use mp_hal_get_ramdom(), which is the function mbedtls_hardware_poll() in mbedtls_port.c. It is changed already for MIMXRT, which used the random number generation from modos already before. There are four more ports where this could be used. Maybe this function can then be moved to another place/file, when it gets port-agnostic.

@dpgeorge

Copy link
Copy Markdown
Member

I spotted at least one typical place to use mp_hal_get_ramdom(), which is the function mbedtls_hardware_poll() in mbedtls_port.c. It is changed already for MIMXRT, which used the random number generation from modos already before. There are four more ports where this could be used. Maybe this function can then be moved to another place/file, when it gets port-agnostic.

Yes, that sounds good. Let's leave it for a follow up PR.

@dpgeorge

Copy link
Copy Markdown
Member

I added a test for os.urandom() which checks negative arguments (as well as 0 and positive values).

@robert-hh

Copy link
Copy Markdown
Contributor Author

Thanks for adding the test. I was wondering whether a .exp file is missing. But it seems that the approach has changed.

@dpgeorge

Copy link
Copy Markdown
Member

I was wondering whether a .exp file is missing. But it seems that the approach has changed.

The approach is still the same. In this case the behaviour matches CPython, so the exp file is generated dynamically as the test is run, via CPython.

robert-hh and others added 3 commits February 24, 2026 23:36
Factor out mp_os_urandom() of each port into extmod/modos.c, which then
calls the port-specific function mp_hal_get_random().

Move mp_hal_get_random() to mphalport where suitable. At the
MIMXRT and SAMD it is left in modos.c, since there are different
implementation depending on the MCU family.

At the ALIF, ESP32, CC3200 and RP2 port the file modos.c was removed,
since it was empty after moving mp_hal_get_random().

Tested for the cc3200, esp32, esp8266, mimxrt, nrf, rp2, samd, stm32
and unix ports. Compiled for the alif and the renesas port.

Signed-off-by: robert-hh <[email protected]>

@dpgeorge dpgeorge left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, it's a really nice clean up / consolidation across the ports.

@dpgeorge
dpgeorge merged commit 6dbabc9 into micropython:master Feb 24, 2026
76 checks passed
@robert-hh

Copy link
Copy Markdown
Contributor Author

Thank you very much.

@projectgus

Copy link
Copy Markdown
Contributor

Thanks @robert-hh! This is indeed a very nice consolidation to have, much appreciated.

@robert-hh
robert-hh deleted the ports_urandom branch February 25, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extmod Relates to extmod/ directory in source ports Relates to multiple ports, or a new/proposed port

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os.urandom(-1) crash

5 participants