Cause of crashing via UObject limit reached?

I’ve encountered a recurring problem with my slight ShooterGame alterations; it seems if I call a combination of two functions, I’ll get a UObject limit reached - calling either of the two functions standalone does not trigger the issue.

I’ve verified it applies when the caller is pure C++ or Blueprint scripting, and have removed the BehaviorTree from the equation. I’ve spent the last 48 hours attempting to narrow down the cause, getting to where I am now, and my next step is to compile the engine from source to debug better if nobody has any ideas!

Here’s the log output:

D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.1\Engine\Source\Runtime\CoreUObject\Private\UObject\WeakObjectPtr.cpp(78): Fatal error:
[Index:1115934332] exceeds maximum number of UObjects, [Block:68111] increase MAX_SERIAL_NUMBER_BLOCKS
UE4Editor.exe has triggered a breakpoint.
UE4Editor.exe has triggered a breakpoint.
[2014.05.29-01.39.10:464][648]LogWindows:Error: appError called: [Index:1115934332] exceeds maximum number of UObjects, [Block:68111] increase MAX_SERIAL_NUMBER_BLOCKS
[2014.05.29-01.39.10:476][648]LogWindows:Error: Windows GetLastError: The operation completed successfully. (0)
[2014.05.29-01.39.10:532][648]LogCrashTracker: 
[2014.05.29-01.39.10:532][648]LogWindows: === Critical error: ===
[2014.05.29-01.39.10:532][648]LogWindows: [Index:1115934332] exceeds maximum number of UObjects, [Block:68111] increase MAX_SERIAL_NUMBER_BLOCKS
[2014.05.29-01.39.10:641][648]LogExit: Executing StaticShutdownAfterError
[2014.05.29-01.39.10:660][648]LogWindows: FPlatformMisc::RequestExit(1)
The thread 0x1be8 has exited with code 3 (0x3).
...

The two functions in question are FindClosestEnemy, which is modified from ShooterGame to simply return the character instead of updating the blackboard directly:

class AShooterCharacter*
AShooterAIController::FindClosestEnemy()
{
	APawn*			my_bot = GetPawn();
	AShooterCharacter*	closest_pawn = NULL;

	if ( my_bot == NULL )
	{
		return NULL;
	}

	const FVector	my_location = my_bot->GetActorLocation();
	float		closest_dist_sq = MAX_FLT;

	for ( FConstPawnIterator iter = GetWorld()->GetPawnIterator(); iter; ++iter )
	{
		AShooterCharacter*	pawn = Cast<AShooterCharacter>(*iter);

		if ( pawn && pawn->IsAlive() && pawn->IsEnemyFor(this) )
		{
			const float	dist_sq = (pawn->GetActorLocation() - my_location).SizeSquared();

			if ( dist_sq < closest_dist_sq )
			{
				closest_dist_sq = dist_sq;
				closest_pawn = pawn;
			}
		}
	}

	return closest_pawn;
}

and the other is the blackboard update function:

void
AShooterAIController::BBUpdateBestEnemy(
	class APawn* InPawn
)
{
	if ( BlackboardComp )
	{
		BlackboardComp->SetValueAsObject(BestEnemyKeyID, InPawn);

		if ( !InPawn )
		{
			BlackboardComp->SetValueAsVector(BestEnemyLocationKeyID, FVector::ZeroVector);
			return;
		}
		
		BlackboardComp->SetValueAsVector(BestEnemyLocationKeyID, InPawn->GetActorLocation());
	}
}

I currently have the blueprint calling a LocateBestEnemy function, which simply calls BBUpdateBestEnemy(FindClosestEnemy()).

It seems when the input Pawn is NULL, there’s no problem, but when it’s a valid actor, it goes to hell - more annoyingly, stepping through in a debugger doesn’t seem to cause the error to manifest, leading me to think it could be a race condition somewhere, causing memory corruption? The code can work anywhere from 0 seconds all the way up to 60 seconds before it actually bombs out, but seems to be exasperated by moving the player around - I’ve noticed it also frequently occurs right when the bot respawns.

There’s no constant increase of UObjects created before the crash, leading me to believe it’s not a leak anywhere.

Regards

Hi stymgade,

Where and how are you defining and setting BestEnemyKeyID and BestEnemyLocationKeyID? These are not in my ShooterGame code.

Hi , these are some of the additions I made (working towards AI improvements) - they’re within the ShooterAIController, protected:

int32 BestEnemyKeyID; int32 BestEnemyLocationKeyID;

They’re set in the same way as the others, within Possess():

BestEnemyKeyID = BlackboardComp->GetKeyID("BestEnemy"); BestEnemyLocationKeyID = BlackboardComp->GetKeyID("BestEnemyLocation");

The values are also initialized right after starting the behavior tree:

BlackboardComp->SetValueAsObject(BestEnemyKeyID, NULL); BlackboardComp->SetValueAsVector(BestEnemyLocationKeyID, FVector::ZeroVector);

If it makes it easier, I can make the whole code + blueprints available from what I’ve done so far!

Hi stymgade,

I was able to get all of the code you provided compiled, and linked it into an existing Blueprint, but I did not see any of the crash behavior that you mentioned. I think I will need to see how your Blueprints are setup.

My best guess would be that you have a BT subtree governed by a blackboard decorator observing one of blackboard keys you modify withing said BT subtree. As a rule of thumb you should not directly influence blackboard with BT nodes - let related code do that so the changes to BT’s state are asynchronous (meaning not happening in one frame). As an experiment try calling BBUpdateBestEnemy with FSimpleDelegateGraphTask::CreateAndDispatchWhenReady and see if it fixes it.

BTW, we have a plan to address that in core BT code.

A minor comment of your code: use FAISystem::InvalidLocation instead of FVector::ZeroVector as “not set” value of vector BB values. BT blackboard checking conditions like “is set” test value against “invalid location” to check if a value is set. Then again I think there’s a bug in 4.1.1 that breaks that, but it’s fixed in 4.2 :smiley:

–mieszko