Dangling Property References in Child Blueprint Classes

This problem has already got a related bug report: UE-45726.

Some background knowledge first: blueprint classes will be compiled and linked for multiple times during the engine’s loading process. While recompiling a blueprint class, the old class will be purged before being replaced by a new one. During the compilation process, properties which will be replicated are collected, and, if there are any inheritances, parent’s replicated properties will be linked to child’s. This mechanism requires parent classes to be compiled and linked always before child classes, otherwise child classes may have invalid properties (dangling property pointers) linked.

The mal-linked properties could ultimately cause a memory access violation in dedicated server games. The symptom could be a crash while checking the PropertyFlags of an invalid property (cf. UE-29614).

It’s worth mentioning that this crash has been reported multiple times in the past (e.g. this and this post), but they were most probably caused by other problems, and could be misleading if you encountered this crash in recent engine builds.

After tracing into the code, I found something suspicious in BlueprintSupport.cpp, around line 340. After compiling a master class with all its dependencies gathered, the depended classes are scheduled to be recompiled, in order to do a re-link to reflect changes in the master class, in reversed order. Because descendant classes are also listed in the dependencies, they are actually recompiled in a specific to generic order. I could not conjecture the original purpose of the person who wrote the reversed iteration (maybe it’s simply easier because you don’t have to reset the iterator in order to reuse it), but in such an order, child classes will be linked to their soon-to-expire parent classes (which will be re-linked right after its child classes), causing dangling links.

After replacing the reversed iteration with a forward one, it worked like a charm. I’ve only made a few test and since this is quite a low-level function, I’m not sure if it might cause any other side issues. I hope staffs in Epic could review this code, and I’d be happy to make a pull request if this is proved to work.