Opened 3 weeks ago

Closed 3 weeks ago

#37418 closed Bug (fixed)

forms.JSONField crashes with RecursionError on deeply nested input

Reported by: Philip Sørensen Owned by: Philip Sørensen
Component: Forms Version: 6.1
Severity: Normal Keywords:
Cc: Philip Sørensen Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

forms.JSONField.to_python() and bound_data() only catch json.JSONDecodeError. When the submitted value is nested more deeply than the recursion limit, json.loads() raises RecursionError instead, so the form crashes (HTTP 500) rather than showing "Enter a valid JSON.". About 4 KB of input is enough, well within DATA_UPLOAD_MAX_MEMORY_SIZE:

>>> from django import forms
>>> forms.JSONField().clean("[" * 100_000 + "]" * 100_000)
RecursionError: maximum recursion depth exceeded while decoding a JSON array from a unicode string

This affects any form or ModelForm with a JSONField, including the admin. The contrib.postgres HStoreField form field has the same pattern.

Patch: also catch RecursionError in those three places, with regression tests.

Change History (6)

comment:1 by Jacob Walls, 3 weeks ago

Has patch: unset
Owner: set to philipsorenson
Status: new → assigned
Triage Stage: Unreviewed → Accepted

Accepted with a caveat that this won't work reliably for free-threading builds, as discussed on the PR.

I don't think we should go further than add this to a list of caveats about free-threading. For instance, I doubt that Django should start rolling its own max_depth checks when this feature is already handled by other serialization libraries. (I think Django should instead be prioritizing the ​new feature request to add swappable JSON serializers. There should be a Trac ticket for that soon.)

In any case, catching this here is harmless.

comment:2 by Jacob Walls, 3 weeks ago

Patch needs improvement: set

comment:3 by Jacob Walls, 3 weeks ago

Has patch: set
Owner: changed from philipsorenson to Philip Sørensen

comment:4 by Jacob Walls, 3 weeks ago

Patch needs improvement: unset
Triage Stage: Accepted → Ready for checkin

in reply to:  1 comment:5 by Jacob Walls, 3 weeks ago

Replying to Jacob Walls:

Accepted with a caveat that this won't work reliably for free-threading builds, as discussed on the PR.

More discussion on the PR attributed the failure to recursion limits configured on the CI runners, rather than free-threading per se, so this part of the commentary should be ignored.

comment:6 by Jacob Walls <jacobtylerwalls@…>, 3 weeks ago

Resolution: → fixed
Status: assigned → closed

In 9014ca5:

Fixed #37418 -- Fixed JSONField/HStoreField crash on deeply nested JSON.

json.loads() raises RecursionError rather than JSONDecodeError when the
input nesting exceeds the interpreter's recursion limit.

Note: See TracTickets for help on using tickets.
Back to Top