Description

When adding an entry to a TMap using UE's property editors, in most cases the new entry comes with a default-initialized key (if such key already exists, the insertion fails). The case of a UENUM defined in C++ is handled differently though, as each new entry comes automatically with the first unused enumerator, which is very welcome. Unfortunately, this special case also has a bug: if the user deletes an existing entry from the middle of the list and then attempts to insert a new one, the following happens:

  • A new entry appears in the correct spot in the map, but with a default-initialized key (even if such key already exists, leading to potentially any number of duplicate keys)
  • The last entry in the map has its key incorrectly overwritten by the new key, and its old key is lost.

A preliminary investigation showed that, in PropertyHandleImpl.cpp:5776, function HasKey() behaves as expected, which allows the code to discover the first unused enumerator correctly. However, right after that, the call "Implementation->AddChild()" reuses map indices that were freed by previous entry deletions, and the new default-initialized item ends up not being in the last position in the internal array storage. The code following that wrongly assumes that the new item is the last one, and updates that wrong item to have the new unique key. As a result, the newly-inserted default-initialized enum is left unchanged, and the last item in the map is wrongly replaced.

 

Steps to Reproduce
  • Edit the code for a C++ project
  • Create a UENUM in C++ with 3 or more items (5 suggested):

UENUM(BlueprintType)
enum class EMyEnum : uint8
{
Enumerator0,
Enumerator1,
Enumerator2,
Enumerator3,
Enumerator4,
};

  • Create an Actor in c++ containing a TMap using the enum above as key:

UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TMap<EMyEnum, FString> MyMap;
};

  • Compile the project and open it in the editor
  • Create a new blueprint actor from the C++ actor
  • In the "Class Defaults" tab:
  • Add 3-5 (or more) entries to the map. They will automatically come with unique keys.
  • Delete one or more entries from the middle of the list
  • Add 1 entry to the map. The result will be incorrect.
  • The last deleted entry will now have the first enumerator as key, even if it is a duplicate
  • The last entry of the map will now have been replaced by the unique key that was supposed to be added.
  • Note 1: The behavior is the same when editing blueprint defaults, or values on an actor instance
  • Note 2: The behavior is the same for a blueprint-defined Map variable
  • Note 3: The behavior is correct when the newly added entry can have the default key
  • Note 4: The behavior is correct for a blueprint-defined Enumeration or any other key types

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-219729 in the post.

1
Login to Vote

Fixed
ComponentUE - Editor - Workflow Systems
Affects Versions5.4.3
Target Fix5.4.3
Fix Commit35178509
CreatedJul 19, 2024
ResolvedJul 30, 2024
UpdatedSep 4, 2024
View Jira Issue