From af46b262b532400d1ff0ce176a969aa6d397193d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 4 Nov 2011 09:08:29 +0100 Subject: [PATCH] More init hardening. --- CMakeLists.txt | 2 +- library/Console-linux.cpp | 10 +++- library/Console-windows.cpp | 49 +++++++++++++++- library/Core.cpp | 63 +++++++++++++++++---- library/FakeSDL-linux.cpp | 5 ++ library/FakeSDL-windows.cpp | 3 + library/VersionInfoFactory.cpp | 10 +++- library/include/dfhack/Console.h | 1 + library/include/dfhack/Core.h | 11 ++-- library/include/dfhack/VersionInfoFactory.h | 3 +- plugins/devel/df2mc | 2 +- plugins/devel/rawdump.cpp | 10 ++-- plugins/prospector.cpp | 14 ++--- 13 files changed, 148 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1210b0c41..2a618aa4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ set(DF_VERSION_MINOR "31") set(DF_VERSION_PATCH "25") set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}") -set(DFHACK_RELEASE "7d") +set(DFHACK_RELEASE "7e") ## where to install things (after the build is done, classic 'make install' or package structure) # the dfhack libraries will be installed here: diff --git a/library/Console-linux.cpp b/library/Console-linux.cpp index d74c48045..e15a6e9cb 100644 --- a/library/Console-linux.cpp +++ b/library/Console-linux.cpp @@ -640,7 +640,6 @@ bool Console::init(bool sharing) return false; } freopen("stdout.log", "w", stdout); - freopen("stderr.log", "w", stderr); d = new Private(); // make our own weird streams so our IO isn't redirected d->dfout_C = fopen("/dev/tty", "w"); @@ -690,11 +689,18 @@ int Console::printerr( const char* format, ... ) va_list args; lock_guard g(*wlock); int ret; - if(!inited) ret = -1; + // also mirror in error log + if(!inited) + { + va_start( args, format ); + ret = vfprintf(stderr, format, args); + va_end(args); + } else { va_start( args, format ); ret = d->vprinterr(format, args); + vfprintf(stderr, format, args); va_end(args); } return ret; diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index 92cfae5a6..4daab5c2f 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -378,6 +378,7 @@ namespace DFHack HANDLE console_in; HANDLE console_out; HWND ConsoleWindow; + HWND MainWindow; WORD default_attributes; // current state enum console_state @@ -402,7 +403,29 @@ Console::Console():std::ostream(0), std::ios(0) Console::~Console() { } +/* +// DOESN'T WORK - locks up DF! +void ForceForegroundWindow(HWND window) +{ + DWORD nForeThread, nAppThread; + + nForeThread = GetWindowThreadProcessId(GetForegroundWindow(), 0); + nAppThread = ::GetWindowThreadProcessId(window,0); + if(nForeThread != nAppThread) + { + AttachThreadInput(nForeThread, nAppThread, true); + BringWindowToTop(window); + ShowWindow(window,3); + AttachThreadInput(nForeThread, nAppThread, false); + } + else + { + BringWindowToTop(window); + ShowWindow(window,3); + } +} +*/ bool Console::init(bool) { d = new Private(); @@ -411,6 +434,21 @@ bool Console::init(bool) CONSOLE_SCREEN_BUFFER_INFO coninfo; FILE *fp; DWORD oldMode, newMode; + DWORD dwTheardId; + + HWND h = ::GetTopWindow(0 ); + while ( h ) + { + DWORD pid; + dwTheardId = ::GetWindowThreadProcessId( h,&pid); + if ( pid == GetCurrentProcessId() ) + { + // here h is the handle to the window + break; + } + h = ::GetNextWindow( h , GW_HWNDNEXT); + } + d->MainWindow = h; // Allocate a console! AllocConsole(); @@ -450,6 +488,8 @@ bool Console::init(bool) std::cin.tie(this); clear(); inited = true; + // DOESN'T WORK - locks up DF! + // ForceForegroundWindow(d->MainWindow); return true; } // FIXME: looks awfully empty, doesn't it? @@ -480,11 +520,18 @@ int Console::printerr( const char* format, ... ) va_list args; lock_guard g(*wlock); int ret; - if(!inited) ret = -1; + // also mirror in error log + if(!inited) + { + va_start( args, format ); + ret = vfprintf(stderr, format, args); + va_end(args); + } else { va_start( args, format ); ret = d->vprinterr(format, args); + vfprintf(stderr, format, args); va_end(args); } return ret; diff --git a/library/Core.cpp b/library/Core.cpp index 62f556e01..3a5df4541 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -174,6 +174,8 @@ void fIOthread(void * iodata) } string first = parts[0]; parts.erase(parts.begin()); + cerr << "Invoking: " << command << endl; + // let's see what we actually got if(first=="help" || first == "?") { @@ -351,7 +353,7 @@ void fIOthread(void * iodata) command_result res = plug_mgr->InvokeCommand(first, parts); if(res == CR_NOT_IMPLEMENTED) { - con.printerr("Invalid command.\n"); + con.printerr("%s is not a recognized command.\n", first.c_str()); clueless_counter ++; } /* @@ -393,6 +395,23 @@ Core::Core() misc_data_mutex=0; }; +void Core::fatal (std::string output, bool deactivate) +{ + stringstream out; + out << output ; + if(deactivate) + out << "DFHack will now deactivate.\n"; + if(con.isInited()) + { + con.printerr("%s", out.str().c_str()); + } + fprintf(stderr, "%s\n", out.str().c_str()); +#ifndef LINUX_BUILD + out << "Check file stderr.log for details\n"; + MessageBox(0,out.str().c_str(),"DFHack error!", MB_OK | MB_ICONERROR); +#endif +} + bool Core::Init() { if(started) @@ -406,30 +425,48 @@ bool Core::Init() #else const char * path = "hack\\Memory.xml"; #endif - vif = new DFHack::VersionInfoFactory(path); + vif = new DFHack::VersionInfoFactory(); + cerr << "Identifying DF version.\n"; + try + { + vif->loadFile(path); + } + catch(Error::All & err) + { + std::stringstream out; + out << "Error while reading Memory.xml:\n"; + out << err.what() << std::endl; + delete vif; + vif = nullptr; + errorstate = true; + fatal(out.str(), true); + return false; + } p = new DFHack::Process(vif); vinfo = p->getDescriptor(); if(!vinfo || !p->isIdentified()) { - cerr << "Not a known DF version. DFHack will now deactivate.\n"; + fatal ("Not a known DF version.\n", true); errorstate = true; delete p; p = NULL; return false; } + cerr << "Version: " << vinfo->getVersion() << endl; + cerr << "Initializing Console.\n"; // init the console. Gui * g = getGui(); - if(g->init) + bool is_text_mode = false; + if(g->init && g->init->graphics.flags.is_set(GRAPHICS_TEXT)) { - if(g->init->graphics.flags.is_set(GRAPHICS_TEXT)) - { - con.init(true); - } - else con.init(false); + is_text_mode = true; } - else con.init(false); + if(con.init(is_text_mode)) + cerr << "Console is running.\n"; + else + fatal ("Console has failed to initialize!\n", false); // dump offsets to a file std::ofstream dump("offsets.log"); @@ -444,18 +481,22 @@ bool Core::Init() AccessMutex = new mutex(); misc_data_mutex=new mutex(); core_cond = new Core::Cond(); + cerr << "Initializing Plugins.\n"; // create plugin manager plug_mgr = new PluginManager(this); + cerr << "Starting IO thread.\n"; // create IO thread IODATA *temp = new IODATA; temp->core = this; temp->plug_mgr = plug_mgr; thread * IO = new thread(fIOthread, (void *) temp); + cerr << "Starting DF input capture thread.\n"; // set up hotkey capture HotkeyMutex = new mutex(); HotkeyCond = new condition_variable(); thread * HK = new thread(fHKthread, (void *) temp); started = true; + cerr << "DFHack is running.\n"; return true; } /// sets the current hotkey command @@ -565,6 +606,8 @@ int Core::Update() // FIXME: needs to terminate the IO threads and properly dismantle all the machinery involved. int Core::Shutdown ( void ) { + if(errorstate) + return true; errorstate = 1; if(plug_mgr) { diff --git a/library/FakeSDL-linux.cpp b/library/FakeSDL-linux.cpp index a5f34e5f2..59ae1bbd4 100644 --- a/library/FakeSDL-linux.cpp +++ b/library/FakeSDL-linux.cpp @@ -132,6 +132,11 @@ DFhackCExport int wgetch(WINDOW *win) static int (*_SDL_Init)(uint32_t flags) = 0; DFhackCExport int SDL_Init(uint32_t flags) { + // reroute stderr + freopen("stderr.log", "w", stderr); + // we don't reroute stdout until we figure out if this should be done at all + // See: Console-linux.cpp + // find real functions _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); diff --git a/library/FakeSDL-windows.cpp b/library/FakeSDL-windows.cpp index f1abe076a..ee569c83c 100644 --- a/library/FakeSDL-windows.cpp +++ b/library/FakeSDL-windows.cpp @@ -694,6 +694,9 @@ DFhackCExport uint32_t SDL_ThreadID(void) // FIXME: this has to be thread-safe. bool FirstCall() { + // reroute stdout and stderr + freopen("stdout.log", "w", stdout); + freopen("stderr.log", "w", stderr); HMODULE realSDLlib = LoadLibrary("SDLreal.dll"); if(!realSDLlib) { diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 2c9bb3201..b2ec00d96 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -97,13 +97,16 @@ inline bool operator>=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, return !(__x < __y); } -VersionInfoFactory::VersionInfoFactory(string path_to_xml) +VersionInfoFactory::VersionInfoFactory() { error = false; - loadFile(path_to_xml); } VersionInfoFactory::~VersionInfoFactory() +{ + clear(); +} +void VersionInfoFactory::clear(void) { // for each stored version, delete for(uint32_t i = 0; i < versions.size();i++) @@ -111,6 +114,8 @@ VersionInfoFactory::~VersionInfoFactory() delete versions[i]; } versions.clear(); + knownVersions.clear(); + error = false; } VersionInfo * VersionInfoFactory::getVersionInfoByMD5(string hash) @@ -768,5 +773,6 @@ bool VersionInfoFactory::loadFile(string path_to_xml) } } error = false; + std::cerr << "Loaded " << versions.size() << " DF versions." << std::endl; return true; } diff --git a/library/include/dfhack/Console.h b/library/include/dfhack/Console.h index f6b09f9b2..e4e2c44f7 100644 --- a/library/include/dfhack/Console.h +++ b/library/include/dfhack/Console.h @@ -164,6 +164,7 @@ namespace DFHack //void beep (void); /// A simple line edit (raw mode) int lineedit(const std::string& prompt, std::string& output, CommandHistory & history ); + bool isInited (void) { return inited; }; private: Private * d; tthread::mutex * wlock; diff --git a/library/include/dfhack/Core.h b/library/include/dfhack/Core.h index 2cc9ff149..e4e2171ab 100644 --- a/library/include/dfhack/Core.h +++ b/library/include/dfhack/Core.h @@ -126,10 +126,10 @@ namespace DFHack /// removes the hotkey command and gives it to the caller thread std::string getHotkeyCmd( void ); - /// adds a named pointer (for later or between plugins) - void RegisterData(void *p,std::string key); - /// returns a named pointer. - void *GetData(std::string key); + /// adds a named pointer (for later or between plugins) + void RegisterData(void *p,std::string key); + /// returns a named pointer. + void *GetData(std::string key); DFHack::Process * p; DFHack::VersionInfo * vinfo; @@ -143,6 +143,9 @@ namespace DFHack bool ncurses_wgetch(int in, int & out); Core(Core const&); // Don't Implement void operator=(Core const&); // Don't implement + // report error to user while failing + void fatal (std::string output, bool will_deactivate); + // 1 = fatal failure bool errorstate; // regulate access to DF struct Cond; diff --git a/library/include/dfhack/VersionInfoFactory.h b/library/include/dfhack/VersionInfoFactory.h index ab3131305..0803a2c7f 100644 --- a/library/include/dfhack/VersionInfoFactory.h +++ b/library/include/dfhack/VersionInfoFactory.h @@ -39,7 +39,7 @@ namespace DFHack { friend class ProcessEnumerator; public: - VersionInfoFactory(std::string path_to_xml); + VersionInfoFactory(); ~VersionInfoFactory(); // memory info entries loaded from a file bool loadFile( std::string path_to_xml); @@ -47,6 +47,7 @@ namespace DFHack VersionInfo * getVersionInfoByMD5(std::string md5string); VersionInfo * getVersionInfoByPETimestamp(uint32_t timestamp); std::vector versions; + void clear( void ); private: void ParseVTable(TiXmlElement* vtable, VersionInfo* mem); void ParseBase (TiXmlElement* base, VersionInfo* mem); diff --git a/plugins/devel/df2mc b/plugins/devel/df2mc index 0f6389f41..ea35678fc 160000 --- a/plugins/devel/df2mc +++ b/plugins/devel/df2mc @@ -1 +1 @@ -Subproject commit 0f6389f4121d6cf3d447fb72a5b561d8d66b0de8 +Subproject commit ea35678fc408dadef196ed82f61c00709a23b914 diff --git a/plugins/devel/rawdump.cpp b/plugins/devel/rawdump.cpp index ba1edde22..0e6cac5bd 100644 --- a/plugins/devel/rawdump.cpp +++ b/plugins/devel/rawdump.cpp @@ -56,13 +56,13 @@ DFhackCExport command_result rawdump_i (Core * c, vector & parameters) { if( index < mats->df_inorganic->size()) { - df_inorganic_material * mat = mats->df_inorganic->at(index); + df_inorganic_type * mat = mats->df_inorganic->at(index); // dump single material con.print("%-3d : [%s] %s\n", index, - mat->Inorganic_ID.c_str(), - mat->STATE_NAME_SOLID.c_str()); - con.print("MAX EDGE: %d\n",mat->MAX_EDGE); + mat->ID.c_str(), + mat->mat.state_name[DFHack::state_solid].c_str()); + con.print("MAX EDGE: %d\n",mat->mat.MAX_EDGE); } else { @@ -74,7 +74,7 @@ DFhackCExport command_result rawdump_i (Core * c, vector & parameters) // dump all materials for(int i = 0; i < mats->df_inorganic->size();i++) { - con.print("%-3d : %s\n",i,mats->df_inorganic->at(i)->Inorganic_ID.c_str()); + con.print("%-3d : %s\n",i,mats->df_inorganic->at(i)->ID.c_str()); } } c->Resume(); diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index ba20dad2d..5e642ed5a 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -198,7 +198,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector & par DFHack::Maps *maps = c->getMaps(); if (!maps->Start()) { - con << "Cannot get map info!" << std::endl; + con.printerr("Cannot get map info!\n"); c->Resume(); return CR_FAILURE; } @@ -208,13 +208,13 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector & par DFHack::Materials *mats = c->getMaterials(); if (!mats->df_inorganic) { - con << "Unable to read inorganic material definitons!" << std::endl; + con.printerr("Unable to read inorganic material definitons!\n"); c->Resume(); return CR_FAILURE; } if (showPlants && !mats->df_organic) { - con << "Unable to read organic material definitons; plants won't be listed!" << std::endl; + con.printerr("Unable to read organic material definitons; plants won't be listed!\n"); showPlants = false; } @@ -234,21 +234,19 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector & par if (!(showSlade && maps->ReadGlobalFeatures(globalFeatures))) { - con << "Unable to read global features; slade won't be listed!" << std::endl; + con.printerr("Unable to read global features; slade won't be listed!\n"); } if (!maps->ReadLocalFeatures(localFeatures)) { - con << "Unable to read local features; adamantine " - << (showTemple ? "and demon temples " : "") - << "won't be listed!" << std::endl; + con.printerr("Unable to read local features; adamantine and demon temples won't be listed.\n" ); } uint32_t vegCount = 0; DFHack::Vegetation *veg = c->getVegetation(); if (showPlants && !veg->Start()) { - con << "Unable to read vegetation; plants won't be listed!" << std::endl; + con.printerr("Unable to read vegetation; plants won't be listed!\n" ); } for(uint32_t z = 0; z < z_max; z++)