godotengine / godotengine/godot

`String.json_escape` does not escape ASCII control codes

Open
#109,482 3 comments 1 reaction 0 assignees View on GitHub
bug topic:core
Dominant language
C++
Stars
117k
Forks
26.8k
PR merge metrics
PR metrics pending

Description

### Tested versions

Reproducible in 4.4.1-stable and master as of writing a3b42d85d27668f8992c0779ed3cc82d13db3dd9

### System information

macOS Sequoia 15.6

### Issue description

`String.json_escape` does not work for ASCII control codes.

The [JSON specification](https://www.ietf.org/rfc/rfc4627.txt) explicitly allows hexadecimal `\u` notation:

> Any character may be escaped. If the character is in the Basic
Multilingual Plane (U+0000 through U+FFFF), then it may be
represented as a six-character sequence: a reverse solidus, followed
by the lowercase letter u, followed by four hexadecimal digits that
encode the character's code point. The hexadecimal letters A though
F can be upper or lowercase. So, for example, a string containing
only a single reverse solidus character may be represented as
"\u005C".

Test code:

```gdscript
func _ready() -> void:
print("\u0001\u0002\u0003\u0004".json_escape())
print("\u0021\u0022\u0023\u0024".json_escape())
```

Expected output:

```
\u0001\u0002\u0003\u0004
!\"#$
```

Actual output:

```

!\"#$
```

Screenshot in case browsers don't want to render those:
Image

The JSON spec explicitly forbids ASCII control codes from being in the string unescaped:

> All Unicode characters may be placed within the
quotation marks except for the characters that must be escaped:
quotation mark, reverse solidus, and the control characters (U+0000
through U+001F).

EDIT: Oh, also, we should escape the extended Unicode control codes (`0x7F` to `0x9F`).

### Steps to reproduce

Paste the above code in a Godot project and run it.

### Minimal reproduction project (MRP)

It's 2 print statements, I won't bother making a MRP ZIP for this.

Contributor guide

Open the contributing guide

Research direction

Start at the String.json_escape entry point and reproduce the issue with the provided GDScript examples. Compare the output with the JSON requirements for U+0000–U+001F and the additionally requested U+007F–U+009F range; done means those control codes are escaped while the existing output remains correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
game-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.