godot-xterm/test/scenes/write_random.tscn

22 lines
406 B
Text
Raw Normal View History

Fix unicode errors Changes `write()` method of native pipe and terminal to accept a PoolByteArray rather than String. This means that `get_string_from_utf8()` is no longer called on data coming from PTY and being sent to Terminal. The terminal state machine already has a UTF8 parser which maintains its state across calls to `write()`. This means that we can write half the bytes of a single unicode character in one call and the remaining half in the next call and the state machine will parse it correctly. On the other hand, the `get_string_from_utf8()` method of Godot's PoolByteArray requires that the array contains completely valid UTF8, otherwise we get errors such as "Unicode error: invalid skip". The data coming from PTY can be arbitrarily split in the middle of a unicode character meaning that we will sometimes get errors when calling `get_string_from_utf8()` on it. This is more likely to occur when there is a large amount of output (i.e. it's more likely to be split). In other cases, the data might intentionally contain invalid unicode such as when printing binary files or random data (e.g. `cat /bin/sh`, `cat /dev/random`). We avoid these errors by passing the PoolByteArray data directly to the terminal state machine. In addition to fixing unicode errors, this commit: - Prevents repeated calls to pipes `_read_cb()` method that would block Godot and result in a crash with the message "ERROR: All memory pool allocations are in use" that resulted from writing data to an ever-increasing number of PoolByteArrays before any of them could be freed. This could be triggered by running the `cat /dev/urandom` command after making the change to `write()` mentioned above. - Prevents memory leaks by freeing libuv buffers after they have been copied to PoolByteArrays. Fixes #55.
2022-08-14 09:45:17 +02:00
[gd_scene load_steps=2 format=2]
[sub_resource type="GDScript" id=1]
script/source = "extends \"res://addons/godot_xterm/terminal.gd\"
var rng := RandomNumberGenerator.new()
func _ready():
rng.seed = 0
func _process(_delta):
for _i in range(4096):
write(PoolByteArray([rng.randi() % 256]))
"
[node name="Terminal" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = SubResource( 1 )