Pārlūkot izejas kodu

Fix the second crash (dynamic_cast failure)

Vadim Markovtsev 10 gadi atpakaļ
vecāks
revīzija
c5ebec0d1f
3 mainītis faili ar 54 papildinājumiem un 42 dzēšanām
  1. 26 27
      client/Client.cpp
  2. 2 2
      lib/Connection.cpp
  3. 26 13
      lib/Connection.h

+ 26 - 27
client/Client.cpp

@@ -59,8 +59,8 @@ template <typename T> class CApplyOnCL;
 class CBaseForCLApply
 {
 public:
-	virtual void applyOnClAfter(CClient *cl, void *pack) const =0; 
-	virtual void applyOnClBefore(CClient *cl, void *pack) const =0; 
+	virtual void applyOnClAfter(CClient *cl, void *pack) const =0;
+	virtual void applyOnClBefore(CClient *cl, void *pack) const =0;
 	virtual ~CBaseForCLApply(){}
 
 	template<typename U> static CBaseForCLApply *getApplier(const U * t=nullptr)
@@ -144,7 +144,7 @@ void CClient::waitForMoveAndSend(PlayerColor color)
 		{
 			logNetwork->traceStream() << "Send battle action to server: " << ba;
 			MakeAction temp_action(ba);
-			sendRequest(&temp_action, color);			
+			sendRequest(&temp_action, color);
 		}
 		return;
 	}
@@ -169,8 +169,8 @@ void CClient::run()
 		while(!terminate)
 		{
 			CPack *pack = serv->retreivePack(); //get the package from the server
-			
-			if (terminate) 
+
+			if (terminate)
 			{
 				vstd::clear_pointer(pack);
 				break;
@@ -178,10 +178,10 @@ void CClient::run()
 
 			handlePack(pack);
 		}
-	} 
+	}
 	//catch only asio exceptions
 	catch (const boost::system::system_error& e)
-	{	
+	{
         logNetwork->errorStream() << "Lost connection to server, ending listening thread!";
         logNetwork->errorStream() << e.what();
 		if(!terminate) //rethrow (-> boom!) only if closing connection was unexpected
@@ -313,7 +313,7 @@ void CClient::loadGame(const std::string & fname, const bool server, const std::
          *serv << ui8(3) << ui8(loadNumPlayers); //load game; one client if single-player
          *serv << fname;
          *serv >> pom8;
-         if(pom8) 
+         if(pom8)
               throw std::runtime_error("Server cannot open the savegame!");
          else
               logNetwork->infoStream() << "Server opened savegame properly.";
@@ -369,7 +369,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 {
 	enum {SINGLE, HOST, GUEST} networkMode = SINGLE;
 
-	if (con == nullptr) 
+	if (con == nullptr)
 	{
 		CServerHandler sh;
 		serv = sh.connectToServer();
@@ -452,7 +452,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 				logNetwork->infoStream() << boost::format("Player %s will be lead by %s") % color % AiToGive;
 				installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
 			}
-			else 
+			else
 			{
 				installNewPlayerInterface(make_shared<CPlayerInterface>(color), color);
 				humanPlayers++;
@@ -495,7 +495,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 // 		nm->giveActionCB(this);
 // 		nm->giveInfoCB(this);
 // 		nm->init();
-// 
+//
 // 		erm = nm; //something tells me that there'll at most one module and it'll be ERM
 // 	}
 }
@@ -503,7 +503,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 void CClient::serialize(COSer & h, const int version)
 {
 	assert(h.saving);
-	h & hotSeat;	
+	h & hotSeat;
 	{
 		ui8 players = playerint.size();
 		h & players;
@@ -513,7 +513,7 @@ void CClient::serialize(COSer & h, const int version)
 			LOG_TRACE_PARAMS(logGlobal, "Saving player %s interface", i->first);
 			assert(i->first == i->second->playerID);
 			h & i->first & i->second->dllName & i->second->human;
-			i->second->saveGame(h, version); 			
+			i->second->saveGame(h, version);
 		}
 	}
 }
@@ -529,7 +529,7 @@ void CClient::serialize(CISer & h, const int version)
 		for(int i=0; i < players; i++)
 		{
 			std::string dllname;
-			PlayerColor pid; 
+			PlayerColor pid;
 			bool isHuman = false;
 
 			h & pid & dllname & isHuman;
@@ -541,7 +541,7 @@ void CClient::serialize(CISer & h, const int version)
 				if(pid == PlayerColor::NEUTRAL)
 				{
 					installNewBattleInterface(CDynLibHandler::getNewBattleAI(dllname), pid);
-					//TODO? consider serialization 
+					//TODO? consider serialization
 					continue;
 				}
 				else
@@ -582,7 +582,7 @@ void CClient::serialize(COSer & h, const int version, const std::set<PlayerColor
 			LOG_TRACE_PARAMS(logGlobal, "Saving player %s interface", i->first);
 			assert(i->first == i->second->playerID);
 			h & i->first & i->second->dllName & i->second->human;
-			i->second->saveGame(h, version); 			
+			i->second->saveGame(h, version);
 		}
 	}
 }
@@ -598,7 +598,7 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
 		for(int i=0; i < players; i++)
 		{
 			std::string dllname;
-			PlayerColor pid; 
+			PlayerColor pid;
 			bool isHuman = false;
 
 			h & pid & dllname & isHuman;
@@ -611,7 +611,7 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
 				{
                     if(playerIDs.count(pid))
                        installNewBattleInterface(CDynLibHandler::getNewBattleAI(dllname), pid);
-					//TODO? consider serialization 
+					//TODO? consider serialization
 					continue;
 				}
 				else
@@ -633,7 +633,7 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
             if(playerIDs.count(pid))
                  installNewPlayerInterface(nInt, pid);
 
-            nInt->loadGame(h, version);       
+            nInt->loadGame(h, version);
 		}
 
 		if(playerIDs.count(PlayerColor::NEUTRAL))
@@ -707,7 +707,7 @@ void CClient::battleStarted(const BattleInfo * info)
 {
 	for(auto &battleCb : battleCallbacks)
 	{
-		if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; })  
+		if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; })
 			||  battleCb.first >= PlayerColor::PLAYER_LIMIT)
 		{
 			battleCb.second->setBattle(info);
@@ -735,7 +735,7 @@ void CClient::battleStarted(const BattleInfo * info)
 	{
 		boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
 		auto bi = new CBattleInterface(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero,
-			Rect((screen->w - 800)/2, 
+			Rect((screen->w - 800)/2,
 			     (screen->h - 600)/2, 800, 600), att, def);
 
 		GH.pushInt(bi);
@@ -798,7 +798,7 @@ void CClient::commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleI
 	catch(...)
 	{
 		handleException();
-	}	
+	}
 }
 
 void CClient::invalidatePaths()
@@ -822,7 +822,6 @@ const CPathsInfo * CClient::getPathsInfo(const CGHeroInstance *h)
 int CClient::sendRequest(const CPack *request, PlayerColor player)
 {
 	static ui32 requestCounter = 0;
-
 	ui32 requestID = requestCounter++;
     logNetwork->traceStream() << boost::format("Sending a request \"%s\". It'll have an ID=%d.")
 				% typeid(*request).name() % requestID;
@@ -882,7 +881,7 @@ void CClient::installNewBattleInterface(shared_ptr<CBattleGameInterface> battleI
 	boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
 	PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
 
-	if(!color) 
+	if(!color)
 		privilagedBattleEventReceivers.push_back(battleInterface);
 
 	battleints[colorUsed] = battleInterface;
@@ -954,7 +953,7 @@ CConnection * CServerHandler::connectToServer()
 #endif
 
 	th.update(); //put breakpoint here to attach to server before it does something stupid
-    
+
 	CConnection *ret = justConnectToServer(settings["server"]["server"].String(), port);
 
 	if(verbose)
@@ -1015,8 +1014,8 @@ CConnection * CServerHandler::justConnectToServer(const std::string &host, const
 		try
 		{
             logNetwork->infoStream() << "Establishing connection...";
-			ret = new CConnection(	host.size() ? host : settings["server"]["server"].String(), 
-									port.size() ? port : boost::lexical_cast<std::string>(settings["server"]["port"].Float()), 
+			ret = new CConnection(	host.size() ? host : settings["server"]["server"].String(),
+									port.size() ? port : boost::lexical_cast<std::string>(settings["server"]["port"].Float()),
 									NAME);
 		}
 		catch(...)

+ 2 - 2
lib/Connection.cpp

@@ -460,7 +460,7 @@ ui16 CTypeList::getTypeID( const std::type_info *type, bool throws ) const
 
 std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to) const
 {
-	if(from == to)
+	if(!strcmp(from->name, to->name))
 		return std::vector<CTypeList::TypeInfoPtr>();
 
 	// Perform a simple BFS in the class hierarchy.
@@ -515,7 +515,7 @@ std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info
 {
 	//This additional if is needed because getTypeDescriptor might fail if type is not registered
 	// (and if casting is not needed, then registereing should no  be required)
-	if(*from == *to)
+	if(!strcmp(from->name(), to->name()))
 		return std::vector<CTypeList::TypeInfoPtr>();
 
 	return castSequence(getTypeDescriptor(from), getTypeDescriptor(to));

+ 26 - 13
lib/Connection.h

@@ -86,7 +86,7 @@ struct TypeComparer
     #ifndef __APPLE__
       return a->before(*b);
     #else
-      return std::string(a->name()) < std::string(b->name());
+      return strcmp(a->name(), b->name()) < 0;
     #endif
     }
 };
@@ -106,6 +106,11 @@ struct PointerCaster : IPointerCaster
 	{
 		From * from = (From*)boost::any_cast<void*>(ptr);
 		To * ret = dynamic_cast<To*>(from);
+		if (ret == nullptr)
+		{
+			// Last resort when RTTI goes mad
+			ret = static_cast<To*>(from);
+		}
 		return (void*)ret;
 	}
 
@@ -117,6 +122,11 @@ struct PointerCaster : IPointerCaster
 		{
 			auto from = boost::any_cast<SmartPt>(ptr);
 			auto ret = std::dynamic_pointer_cast<To>(from);
+			if (!ret)
+			{
+				// Last resort when RTTI goes mad
+				ret = std::static_pointer_cast<To>(from);
+			}
 			return ret;
 		}
 		catch(std::exception &e)
@@ -173,7 +183,7 @@ private:
 		auto typesSequence = castSequence(fromArg, toArg);
 
 		boost::any ptr = inputPtr;
-		for(int i = 0; i < (int)typesSequence.size() - 1; i++)
+		for(int i = 0; i < static_cast<int>(typesSequence.size()) - 1; i++)
 		{
 			auto &from = typesSequence[i];
 			auto &to = typesSequence[i + 1];
@@ -182,7 +192,7 @@ private:
 				THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
 
 			auto &caster = casters.at(castingPair);
-			ptr = (*caster.*CastingFunction)(ptr); //Why does unique_ptr does not have operator->* ..?
+			ptr = (*caster.*CastingFunction)(ptr); //Why does unique_ptr not have operator->* ..?
 		}
 
 		return ptr;
@@ -225,10 +235,14 @@ public:
 		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
 		auto derivedType = getTypeInfo(inputPtr);
 
-		if(baseType == *derivedType)
-			return (void*)inputPtr;
+		if (!strcmp(baseType.name(), derivedType->name()))
+		{
+			return const_cast<void*>(reinterpret_cast<const void*>(inputPtr));
+		}
 
-		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>((void*)inputPtr, &baseType, derivedType));
+		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(
+			const_cast<void*>(reinterpret_cast<const void*>(inputPtr)), &baseType,
+			derivedType));
 	}
 
 	template<typename TInput>
@@ -237,7 +251,7 @@ public:
 		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
 		auto derivedType = getTypeInfo(inputPtr.get());
 
-		if(baseType == *derivedType)
+		if (!strcmp(baseType.name(), derivedType->name()))
 			return inputPtr;
 
 		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, &baseType, derivedType);
@@ -653,16 +667,15 @@ public:
 	};
 
 	template <typename T>
-	class CPointerSaver : public CBasicPointerSaver
+	class CPointerSaver : public CBasicPointerSaver
 	{
 	public:
 		void savePtr(CSaverBase &ar, const void *data) const override
-		{
+		{
 			COSer &s = static_cast<COSer&>(ar);
-			const T *ptr = static_cast<const T*>(data);
-
+			const T *ptr = static_cast<const T*>(data);
 			//T is most derived known type, it's time to call actual serialize
-			const_cast<T&>(*ptr).serialize(s,version);
+			const_cast<T*>(ptr)->serialize(s,version);
 		}
 	};
 
@@ -772,7 +785,7 @@ public:
 
 		//write type identifier
 		ui16 tid = typeList.getTypeID(data);
-		*this << tid;
+		*this << tid;
 
 		this->savePointerHlp(tid, data);
 	}