Crash at FMallocTBB::Malloc

Hello

I have been experiencing a crash for a while. I tried to find the source of the problem, but no luck so far.

Here is what I am doing:

  • Create an FInteractiveProcess
  • Start reading and writing through pipes with the process,
  • After done create another process and do the whole stuff again.

Everything works very fine for a while, but at some point seemingly random crashes happen.

Note: I will provide more info if needed.

Some SS for crash informations(I added some from Qt Creator hoping to get more info):

Here is how I use and communicate with that FInteractiveProcess. Please don’t care about the naming of my classes. Also chess engines are some sort of console programs that communicates through pipes. Their entire purpose is to play chess games.


    class CHESSGAME_API ChessEngineHolder
    {
    ...
    ...
    private:
    	// Holds pointer to interactive process
    	TSharedPtr<FInteractiveProcess> CEProcess;
    ...
    }

~~~~~~~ChessEngineHolder.cpp file~~~~~~~

    bool ChessEngineHolder::Launch(UChessEngineCommunicator *ChessEngineCommunicator,
    							   const FString &Path,
    							   const FString &FileName,
    							   bool isTestLaunch)
    {
    	// If it is running already
    	if (CEProcess.IsValid()) {
    		return false;
    	}
    
    	CECommunicator = ChessEngineCommunicator;
    
    	ChessEngineInfo.EngineFileName = FileName;
    
    	CEProcess = TSharedPtr<FInteractiveProcess>(new FInteractiveProcess(Path, "", true, true));
    
    	if (!CEProcess.IsValid() || !CEProcess->Launch()) {
    		return false;
    	}
    
    	if (isTestLaunch) {
    		CEProcess->OnOutput().BindRaw(this, &ChessEngineHolder::ProcessTest);
    	}
    	else {
    		CEProcess->OnOutput().BindRaw(this, &ChessEngineHolder::OnProcessOutput);
    		CEProcess->OnCompleted().BindRaw(this, &ChessEngineHolder::OnProcessCompleted);
    	}
    
    	// This needs to be sent like this and SendCommandToCE should not be used. Because
    	// SendCommandToCE checks if bIsReady is true and not send the command
    	// if it is not. So sending uci command by SendCommandToCE would be suicide!
    	CEProcess->SendWhenReady("uci");
    
    	return true;
    }
    
    void ChessEngineHolder::SendCommandToCE(const FString &Command, bool isTestRun)
    {
    	if (!isTestRun) {
    		if (CEProcess.IsValid() && CEProcess->IsRunning()) {
    			if (bIsReady) {
    				UE_LOG(LogChessEngineHolder, Log, TEXT("Parent: %s"), *Command);
    				CEProcess->SendWhenReady(Command);
    			}
    			else {
    				YetNotSentCommands.Add(Command);
    			}
    		}
    	}
    	else {
    		if (CEProcess.IsValid() && CEProcess->IsRunning()) {
    			UE_LOG(LogChessEngineHolder, Log, TEXT("Parent: %s"), *Command);
    			CEProcess->SendWhenReady(Command);
    		}
    	}
    }
    
    void ChessEngineHolder::OnProcessOutput(FString Message)
    {
    	/*
    	FFunctionGraphTask::CreateAndDispatchWhenReady([&, Message]() {
    		// code here runs on game thread
    		UE_LOG(LogChessEngineHolder, Log, TEXT("ChessEngine: %s"), *Message);
    	}, TStatId(), NULL, ENamedThreads::GameThread);
    	*/
    
    	if (CEProcess.IsValid() && CEProcess->IsRunning()) {
    		int32 From = Message.Find("bestmove ");
    		if (From >= 0) {
    			if (CECommunicator && CECommunicator->IsValidLowLevelFast())
    				CECommunicator->BestMoveReceived(this, Message);
    			return;
    		}
    
    		From = Message.Find("currmove");
    		if (From >= 0) {
    			if (CECommunicator && CECommunicator->IsValidLowLevelFast())
    				CECommunicator->ChessEngineIsCalculating(this, Message);
    			return;
    		}
    
    		From = Message.Find("uciok");
    		if (From >= 0) {
    			// This needs to be sent like this and SendCommandToCE should not be used. Because
    			// SendCommandToCE checks if bIsReady is true and not send the command
    			// if it is not. So sending isready command by SendCommandToCE would be suicide!
    			CEProcess->SendWhenReady("isready");
    			return;
    		}
    
    		From = Message.Find("readyok");
    		if (From >= 0) {
    			// Be sure to make bIsReady true before calling SendCommandToCE("ucinewgame")
    			bIsReady = true;
    			// Send yet not sent commands to chess engine and empty the array
    			for (const FString &command : YetNotSentCommands) {
    				SendCommandToCE(command);
    			}
    			YetNotSentCommands.Empty();
    			return;
    		}
    	}
    }

~~~~~~~CECommunication.h file~~~~~~~

    UCLASS(BlueprintType, Blueprintable)
    class CHESSGAME_API UChessEngineCommunicator : public UObject
    {
    	GENERATED_BODY()
    
    public:
    	UChessEngineCommunicator();
            ...
    private:
    	TSharedPtr<ChessEngineHolder> ChessEngine0;
    	TSharedPtr<ChessEngineHolder> ChessEngine1;
            ...
    };

~~~~~~~CECommunication.cpp file~~~~~~~

    void UChessEngineCommunicator::LaunchChessEngine(const FString &EngineFileName)
    {
    	if (this->IsValidLowLevelFast() == false)
    		return;
    
    	int32 which = -1;
    	for (int32 i = 0; i < ChessEngineExecutables.Num(); i++) {
    		if (ChessEngineExecutables[i] == EngineFileName) {
    			which = i;
    			break;
    		}
    	}
    
    	if (which < 0) {
    		UE_LOG(LogTemp, Warning, TEXT("Invalid CE File Name: %s"), *EngineFileName);
    		return;
    	}
    
    	FString tempPathToCE = PathToCEFolder;
    	tempPathToCE.Append(ChessEngineExecutables[which]);
    
    	if (ChessEngine0.IsValid() == false) {
    		ChessEngine0 = TSharedPtr<ChessEngineHolder>(new ChessEngineHolder());
    		if (ChessEngine0.IsValid()) {
    			ChessEngine0->Launch(this, tempPathToCE, ChessEngineExecutables[which], false);
    		}
    		else {
    			UE_LOG(LogTemp, Warning, TEXT("CE can't be initialized: %s"), *EngineFileName);
    		}
    	}
    	else if (ChessEngine1.IsValid() == false) {
    		ChessEngine1 = TSharedPtr<ChessEngineHolder>(new ChessEngineHolder());
    		if (ChessEngine1.IsValid()) {
    			ChessEngine1->Launch(this, tempPathToCE, ChessEngineExecutables[which], false);
    		}
    		else {
    			UE_LOG(LogTemp, Warning, TEXT("CE can't be initialized: %s"), *EngineFileName);
    		}
    	}
    	else {
    		UE_LOG(LogTemp, Warning, TEXT("Both CE slots are occupied, CE can't be initialized: %s"), *EngineFileName);
    	}
    }
    
    void UChessEngineCommunicator::StopChessEngines()
    {
    	if (ChessEngine0.IsValid()) {
    		ChessEngine0->SendCommandToCE("quit");
    		ChessEngine0.Reset();
    	}
    
    	if (ChessEngine1.IsValid()) {
    		ChessEngine1->SendCommandToCE("quit");
    		ChessEngine1.Reset();
    	}
    }
    
    void UChessEngineCommunicator::BestMoveReceived(ChessEngineHolder * ChessEngine, const FString &Message)
    {
    	FChessMove2 BestMoveReceivedMove = GetBestMove(Message);
    	if (ChessEngine && ChessEngine == ChessEngine0.Get()) {
    		FFunctionGraphTask::CreateAndDispatchWhenReady([&, BestMoveReceivedMove]() {
    			// code here runs on game thread
    			OnBestMoveReceived.Broadcast(0, BestMoveReceivedMove);
    		}, TStatId(), NULL, ENamedThreads::GameThread);
    	}
    	else if (ChessEngine && ChessEngine == ChessEngine1.Get()) {
    		FFunctionGraphTask::CreateAndDispatchWhenReady([&, BestMoveReceivedMove]() {
    			// code here runs on game thread
    			OnBestMoveReceived.Broadcast(1, BestMoveReceivedMove);
    		}, TStatId(), NULL, ENamedThreads::GameThread);
    	}
    }

I found some problems and solved them. But not sure if these were the solutions to my problem. Will turn back at this comment to inform.

EDIT: Okay, it didn’t fix anything :frowning: I still need to work on it.

I have solved the problem.

The issue was occurring, because sometimes the messages I write to pipe through FInteractiveProcess was longer than the buffer size of the pipe, which caused those crashes. No more problems regarding that.