godotengine / godotengine/godot

Erasing a freed object from a typed array or dictionary fails and prints an error

Open
#110,511 10 comments 13 reactions 0 assignees View on GitHub
bug topic:core topic:gdscript
Dominant language
C++
Stars
117k
Forks
26.8k
PR merge metrics
PR metrics pending

Description

### Tested versions

v4.4.1.stable.official [49a5bc7b6]

### System information

Godot v4.4.1.stable - Windows 11 (build 26100) - Multi-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 4060 Laptop GPU (NVIDIA; 32.0.15.6607) - AMD Ryzen AI 9 HX 370 w/ Radeon 890M (24 threads)

### Issue description

When trying to erase an object from a typed array or dictionary, Godot fails to erase it and prints an error message. For arrays, the object can only be removed using `remove_at()`. For dictionaries, the object simply cannot be removed.

```gdscript
func _ready() -> void:
untyped()
typed()

func untyped() -> void:
var dict := {}
var array := []
var obj := Object.new()

dict[obj] = 1
array.append(obj)

obj.free()

dict.erase(obj) # fine
array.erase(obj) # fine

print(dict) # prints { }
print(array) # prints []

func typed() -> void:
var dict: Dictionary[Object, int] = {}
var array: Array[Object] = []
var obj := Object.new()

dict[obj] = 1
array.append(obj)

obj.free()

dict.erase(obj) # error
array.erase(obj) # error

print(dict) # prints { : 0 }
print(array) # prints []

array.remove_at(0) # fine
print(array) # prints []
```

Erasing the freed object from an untyped array or dictionary is fine, and `untyped()` runs without errors. However, when the array or dictionary is typed, calling `erase()` fails and prints the following errors:
```
E 0:00:01:327 main.gd:34 @ typed(): Attempted to erase an invalid (previously freed?) object instance into a 'TypedDictionary.Key'.
Parameter "object" is null.
./core/variant/container_type_validate.h:122 @ validate_object()
main.gd:34 @ typed()
main.gd:6 @ _ready()
E 0:00:01:327 main.gd:34 @ typed(): Condition "!_p->typed_key.validate(key, "erase")" is true. Returning: false
core/variant/dictionary.cpp:238 @ erase()
main.gd:34 @ typed()
main.gd:6 @ _ready()
E 0:00:01:327 main.gd:35 @ typed(): Attempted to erase an invalid (previously freed?) object instance into a 'TypedArray'.
Parameter "object" is null.
core/variant/container_type_validate.h:122 @ validate_object()
main.gd:35 @ typed()
main.gd:6 @ _ready()
E 0:00:01:327 main.gd:35 @ typed(): Condition "!_p->typed.validate(value, "erase")" is true.
core/variant/array.cpp:328 @ erase()
main.gd:35 @ typed()
main.gd:6 @ _ready()
E 0:00:01:327 main.gd:37 @ typed(): Attempted to use `operator[]` an invalid (previously freed?) object instance into a 'TypedDictionary.Key'.
Parameter "object" is null.
./core/variant/container_type_validate.h:122 @ validate_object()
main.gd:37 @ typed()
main.gd:6 @ _ready()
```

Note that the last error occurs due to #110509.

This wouldn't be an issue since you're not really supposed to have references to freed objects anyway but the only alternative is creating a new array or dictionary and using `assign()` which isn't ideal.

### Steps to reproduce

1. Create an array or dictionary and type it, e.g. `var dict: Dictionary[Object, int] = {}`.
2. Add an object as a key to the dictionary, or append it to the array.
3. Free the object.
4. Try calling `dict.erase(object)` or `array.erase(object)`.

### Minimal reproduction project (MRP)

[mrp.zip](https://github.com/user-attachments/files/22319382/mrp.zip)

Contributor guide

Open the contributing guide

Research direction

Start with the minimal reproduction project and inspect erase() in core/variant/array.cpp and core/variant/dictionary.cpp, along with validation in core/variant/container_type_validate.h. Reproduce the typed Array and Dictionary cases after freeing the Object. Done means erase removes the freed object from both typed containers without validation errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, godot
Domain
game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.