Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using an invalid trace file path crashes with an access violation #22

Open
kweatherman opened this issue Nov 20, 2022 · 1 comment
Open

Comments

@kweatherman
Copy link

kweatherman commented Nov 20, 2022

If you try to load an invalid trace file path, or anything that triggers an internal error message it will result in an access violation crash.
This is because of a missing "TTD::ErrorReporting" class with callbacks we need to add.

To fix this we need to first define the class.
It's actually pretty simple to locate if you have symbols.
The totally virtual base class is "TTD::ErrorReporting" ??_7ErrorReporting@TTD@@6B@
The actual derived instance is "TtdTargetInfo::DbgErrorReporting" ??_7DbgErrorReporting@TtdTargetInfo@@6B@

Recreated class:

namespace TTD
{
	// Error output callbacks for internal TTD errors
	class ErrorReporting
	{			
	public:
		virtual ~ErrorReporting() {}
		virtual void PrintError(const std::string &error) {}
		virtual void VPrintError(LPCSTR format, ...) {}	
	};
	static_assert(sizeof(ErrorReporting) == sizeof(ULONG_PTR), "Should be equal the size of a vftable");
}	

By declaring all the members virtual in their original order, we will end up with virtual class with a single vftable (no need for wrappers or other tricks). Thus the size of the class will be sizeof(ULONG_PTR).

Then down in the "ReplayEngine" class we can now define "RegisterDebugModeAndLogging":

namespace TTD
{
	namespace Replay
	{
		enum DebugModeType
		{
			DefaultMode = 0,
		};

		class ReplayEngine
		{
		public:
		    ...
		    // [46]: public: virtual void TTD::Replay::ReplayEngine::RegisterDebugModeAndLogging(enum TTD::Replay::DebugModeType,class TTD::ErrorReporting *)
		    virtual void RegisterDebugModeAndLogging(TTD::Replay::DebugModeType, class TTD::ErrorReporting*);
		    ...
		};
	}
}

Don't know if there is any more "DebugModeType", in code seen is only a '0' type which I name "DefaultMode".

Now after creating a class instance, somewhere around here ReplayEngine::ReplayEngine() we can add this handler before returning.

// Set internal ErrorReporting callbacks to avoid crash when trace file path is invalid, etc.
this->engine->IReplayEngine->RegisterDebugModeAndLogging(TTD::Replay::DefaultMode, new TTD::ErrorReporting());

Now after a failed ->Initialize(wchar_t const*) call it will not crash, and we can do a HRESULT_FROM_WIN32(GetLastError()) and we'll will get: a 0x80070002 "The system cannot find the file specified.".

@kweatherman
Copy link
Author

kweatherman commented Nov 20, 2022

Now if you want to see the debug output to a console version you can instead of just blanks one can do:

class ErrorReporting
{			
public:
	virtual ~ErrorReporting() {}
	virtual void PrintError(const std::string &error)
	{
		puts(error.c_str());
	}
	virtual void VPrintError(__in LPCSTR format, ...)
	{
		va_list args;
		va_start(args, format);
		vprintf_s(format, args);
		va_end(args);
	}	
};

One caveat though it will crash in the "PrintError" function while debugging because the class fields (the data members) in "std::string" are different between the debug and the release versions. Of course the binary code we have is always release.

Now.. to get around this one can do a simple recreation that is always the release size:

struct std_string
{
	union
	{
		LPSTR ptr;		// 00
		char buffer[16];	// 08
	};
	size_t size;			// 10
	size_t allocated;		// 18

	__forceinline const char* c_str()
	{
		if (allocated > 10)
			return ptr;
		else
			return buffer;
	}
};

Just replace the "const std::string &error" with "std_string &error".

Interesting, but didn't find the internal debug output particularly useful.

@kweatherman kweatherman changed the title Using an invalid trace file path crashed with access violation Using an invalid trace file path crashes with an access violation Nov 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant