From 9484815960fc29305b1d1a62607e001b4df8b327 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Wed, 2 Jan 2019 03:30:49 -0500 Subject: [PATCH] Cache DataDir when C++11 dynamic init is available (GH #760) --- test.cpp | 11 +++++++++ validate.h | 66 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/test.cpp b/test.cpp index 843342b6..3f5d1ee1 100644 --- a/test.cpp +++ b/test.cpp @@ -75,6 +75,7 @@ NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(Test) const int MAX_PHRASE_LENGTH=250; +std::string g_argvPathHint=""; void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed); std::string RSAEncryptString(const char *pubFilename, const char *seed, const char *message); @@ -149,6 +150,16 @@ int scoped_main(int argc, char *argv[]) cin.set_safe_flag(stream_MT::unsafe_object); #endif + // A hint to help locate TestData/ and TestVectors/ after install. + g_argvPathHint = argc > 0 ? argv[0] : ""; +#if defined(AT_EXECFN) + if (getauxval(AT_EXECFN)) + g_argvPathHint = getauxval(AT_EXECFN); +#endif + std::string::size_type pos = g_argvPathHint.find_last_of("\\/"); + if (pos != std::string::npos) + g_argvPathHint.erase(pos+1); + try { RegisterFactories(All); diff --git a/validate.h b/validate.h index d4f78997..d49a8dea 100644 --- a/validate.h +++ b/validate.h @@ -20,6 +20,12 @@ NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(Test) +// A hint to help locate TestData/ and TestVectors/ after install. Due to +// execve the path can be malicious. If the path is ficticous then we move +// onto the next potential path. Also note we only read from the path; we +// never write through it. Storage for the string is in test.cpp. +extern std::string g_argvPathHint; + bool ValidateAll(bool thorough); bool TestSettings(); bool TestOS_RNG(); @@ -205,10 +211,10 @@ inline std::string TimeToString(const time_t& t) // Cleanup whitespace std::string::size_type pos = 0; - while (!str.empty() && std::isspace(*(str.end()-1))) + while (!str.empty() && std::isspace(str[str.length()-1])) {str.erase(str.end()-1);} while (!str.empty() && std::string::npos != (pos = str.find(" ", pos))) - { str.erase(pos, 1); } + {str.erase(pos, 1);} return str; } @@ -252,46 +258,60 @@ inline int StringToValue(const std::string& str) inline std::string AddSeparator(std::string str) { - const char last = (str.empty() ? '\0' : *str.end()-1); + const char last = (str.empty() ? '\0' : str[str.length()-1]); if (last != '/' && last != '\\') return str + "/"; return str; } -// Ideally we would cache the directory and just add the prefix -// to subsequent calls, but ... Static Initialization Order Fiasco +static std::string GetDataDir() +{ + std::ifstream file; + std::string name, filename = "TestData/usage.dat"; + +#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH + name = AddSeparator(g_argvPathHint) + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(g_argvPathHint); +#endif +#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH + // Look in $ORIGIN/../share/. This is likely a Linux install directory. + name = AddSeparator(g_argvPathHint) + std::string("../share/cryptopp/") + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(g_argvPathHint) + std::string("../share/cryptopp/"); +#endif + return "./"; +} + inline std::string DataDir(const std::string& filename) { std::string name; std::ifstream file; -#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH - // Data files in PWD are probably the newest. This is probably a build directory. - name = std::string("./") + filename; - file.open(name.c_str()); - if (file.is_open()) - return name; -#endif + #ifdef CRYPTOPP_DATA_DIR - // Honor the user's setting next. This is likely an install directory if it is not "./". + // Honor CRYPTOPP_DATA_DIR. This is likely an install directory if it is not "./". name = AddSeparator(CRYPTOPP_DATA_DIR) + filename; file.open(name.c_str()); if (file.is_open()) return name; #endif -#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH - // Look in /usr/local/bin/share/. This is LSB and default install directory for users. - name = std::string("/usr/local/share/cryptopp/") + filename; - file.open(name.c_str()); - if (file.is_open()) - return name; -#endif -#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH - // Finally look in $ORIGIN/../share/. This is likely a Linux install directory for users. - name = std::string("../share/cryptopp/") + filename; + +#if CRYPTOPP_CXX11_DYNAMIC_INIT + static std::string path = AddSeparator(GetDataDir()); + name = path + filename; + file.open(name.c_str()); + if (file.is_open()) + return name; +#else + // Avoid static initialzation problems + name = AddSeparator(GetDataDir()) + filename; file.open(name.c_str()); if (file.is_open()) return name; #endif + // This will cause the expected exception in the caller return filename; }