Commit 8d3797cd authored by Andreas Schuh's avatar Andreas Schuh

Fix VS security warnings using SafeGetEnv and SafeFOpen utility functions.

parent 8d93bca2
...@@ -35,13 +35,5 @@ ...@@ -35,13 +35,5 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Windows port // Windows port
#ifdef _WIN32 #ifdef _WIN32
// This must be defined before the windows.h is included.
// It's needed for mutex.h, to give access to the TryLock method.
# if !defined(_WIN32_WINNT) && !(defined( __MINGW32__) || defined(__MINGW64__))
# define _WIN32_WINNT 0x0400
# endif
# if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
# endif
# include "windows_port.h" # include "windows_port.h"
#endif #endif
...@@ -992,8 +992,8 @@ static string ReadFileIntoString(const char* filename) { ...@@ -992,8 +992,8 @@ static string ReadFileIntoString(const char* filename) {
const int kBufSize = 8092; const int kBufSize = 8092;
char buffer[kBufSize]; char buffer[kBufSize];
string s; string s;
FILE* fp = fopen(filename, "r"); FILE* fp;
if (!fp) PFATAL(filename); if ((errno = SafeFOpen(&fp, filename, "r") != 0)) PFATAL(filename);
size_t n; size_t n;
while ( (n=fread(buffer, 1, kBufSize, fp)) > 0 ) { while ( (n=fread(buffer, 1, kBufSize, fp)) > 0 ) {
if (ferror(fp)) PFATAL(filename); if (ferror(fp)) PFATAL(filename);
...@@ -1137,8 +1137,8 @@ string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval, ...@@ -1137,8 +1137,8 @@ string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
} }
const string envname = string("FLAGS_") + string(flagname); const string envname = string("FLAGS_") + string(flagname);
const char* envval = getenv(envname.c_str()); string envval;
if (!envval) { if (!SafeGetEnv(envname.c_str(), envval)) {
if (errors_are_fatal) { if (errors_are_fatal) {
error_flags_[flagname] = (string(kError) + envname + error_flags_[flagname] = (string(kError) + envname +
" not found in environment\n"); " not found in environment\n");
...@@ -1147,15 +1147,14 @@ string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval, ...@@ -1147,15 +1147,14 @@ string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
} }
// Avoid infinite recursion. // Avoid infinite recursion.
if ((strcmp(envval, "fromenv") == 0) || if (envval == "fromenv" || envval == "tryfromenv") {
(strcmp(envval, "tryfromenv") == 0)) {
error_flags_[flagname] = error_flags_[flagname] =
StringPrintf("%sinfinite recursion on environment flag '%s'\n", StringPrintf("%sinfinite recursion on environment flag '%s'\n",
kError, envval); kError, envval.c_str());
continue; continue;
} }
msg += ProcessSingleOptionLocked(flag, envval, set_mode); msg += ProcessSingleOptionLocked(flag, envval.c_str(), set_mode);
} }
return msg; return msg;
} }
...@@ -1335,14 +1334,15 @@ string CommandLineFlagParser::ProcessOptionsFromStringLocked( ...@@ -1335,14 +1334,15 @@ string CommandLineFlagParser::ProcessOptionsFromStringLocked(
template<typename T> template<typename T>
T GetFromEnv(const char *varname, const char* type, T dflt) { T GetFromEnv(const char *varname, const char* type, T dflt) {
const char* const valstr = getenv(varname); std::string valstr;
if (!valstr) if (SafeGetEnv(varname, valstr)) {
return dflt; FlagValue ifv(new T, type, true);
FlagValue ifv(new T, type, true); if (!ifv.ParseFrom(valstr.c_str())) {
if (!ifv.ParseFrom(valstr)) ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n",
ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n", varname, valstr.c_str());
varname, valstr); }
return OTHER_VALUE_AS(ifv, T); return OTHER_VALUE_AS(ifv, T);
} else return dflt;
} }
bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) { bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) {
...@@ -1754,8 +1754,8 @@ bool ReadFlagsFromString(const string& flagfilecontents, ...@@ -1754,8 +1754,8 @@ bool ReadFlagsFromString(const string& flagfilecontents,
// TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName() // TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName()
bool AppendFlagsIntoFile(const string& filename, const char *prog_name) { bool AppendFlagsIntoFile(const string& filename, const char *prog_name) {
FILE *fp = fopen(filename.c_str(), "a"); FILE *fp;
if (!fp) { if (SafeFOpen(&fp, filename.c_str(), "a") != 0) {
return false; return false;
} }
...@@ -1813,10 +1813,18 @@ uint64 Uint64FromEnv(const char *v, uint64 dflt) { ...@@ -1813,10 +1813,18 @@ uint64 Uint64FromEnv(const char *v, uint64 dflt) {
double DoubleFromEnv(const char *v, double dflt) { double DoubleFromEnv(const char *v, double dflt) {
return GetFromEnv(v, "double", dflt); return GetFromEnv(v, "double", dflt);
} }
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4996) // ignore getenv security warning
#endif
const char *StringFromEnv(const char *varname, const char *dflt) { const char *StringFromEnv(const char *varname, const char *dflt) {
const char* const val = getenv(varname); const char* const val = getenv(varname);
return val ? val : dflt; return val ? val : dflt;
} }
#ifdef _MSC_VER
# pragma warning(pop)
#endif
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
...@@ -324,6 +324,33 @@ inline std::string StringPrintf(const char* format, ...) { ...@@ -324,6 +324,33 @@ inline std::string StringPrintf(const char* format, ...) {
return output; return output;
} }
inline bool SafeGetEnv(const char *varname, std::string &valstr)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
char *val;
size_t sz;
if (_dupenv_s(&val, &sz, varname) != 0 || !val) return false;
valstr = val;
free(val);
#else
const char * const val = getenv(varname);
if (!val) return false;
valstr = val;
#endif
return true;
}
inline errno_t SafeFOpen(FILE **fp, const char* fname, const char *mode)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
return fopen_s(fp, fname, mode);
#else
assert(fp != NULL);
*fp = fopen(fname, mode);
return errno;
#endif
}
} // namespace GFLAGS_NAMESPACE } // namespace GFLAGS_NAMESPACE
......
...@@ -44,12 +44,20 @@ ...@@ -44,12 +44,20 @@
// These call the windows _vsnprintf, but always NUL-terminate. // These call the windows _vsnprintf, but always NUL-terminate.
#if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */ #if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4996) // ignore _vsnprintf security warning
#endif
int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
if (size == 0) // not even room for a \0? if (size == 0) // not even room for a \0?
return -1; // not what C99 says to do, but what windows does return -1; // not what C99 says to do, but what windows does
str[size-1] = '\0'; str[size-1] = '\0';
return _vsnprintf(str, size-1, format, ap); return _vsnprintf(str, size-1, format, ap);
} }
#ifdef _MSC_VER
# pragma warning(pop)
#endif
int snprintf(char *str, size_t size, const char *format, ...) { int snprintf(char *str, size_t size, const char *format, ...) {
int r; int r;
...@@ -59,4 +67,5 @@ int snprintf(char *str, size_t size, const char *format, ...) { ...@@ -59,4 +67,5 @@ int snprintf(char *str, size_t size, const char *format, ...) {
va_end(ap); va_end(ap);
return r; return r;
} }
#endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */ #endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */
...@@ -42,8 +42,14 @@ ...@@ -42,8 +42,14 @@
#include "config.h" #include "config.h"
// This must be defined before the windows.h is included.
// It's needed for mutex.h, to give access to the TryLock method.
# if !defined(_WIN32_WINNT) && !(defined( __MINGW32__) || defined(__MINGW64__))
# define _WIN32_WINNT 0x0400
# endif
// We always want minimal includes
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN /* We always want minimal includes */ # define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
#include <direct.h> /* for mkdir */ #include <direct.h> /* for mkdir */
...@@ -65,6 +71,10 @@ extern int GFLAGS_DLL_DECL safe_vsnprintf(char *str, size_t size, ...@@ -65,6 +71,10 @@ extern int GFLAGS_DLL_DECL safe_vsnprintf(char *str, size_t size,
#define va_copy(dst, src) (dst) = (src) #define va_copy(dst, src) (dst) = (src)
#endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */ #endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4996) // ignore getenv security warning
#endif
inline void setenv(const char* name, const char* value, int) { inline void setenv(const char* name, const char* value, int) {
// In windows, it's impossible to set a variable to the empty string. // In windows, it's impossible to set a variable to the empty string.
// We handle this by setting it to "0" and the NUL-ing out the \0. // We handle this by setting it to "0" and the NUL-ing out the \0.
...@@ -86,6 +96,9 @@ inline void setenv(const char* name, const char* value, int) { ...@@ -86,6 +96,9 @@ inline void setenv(const char* name, const char* value, int) {
*getenv(name) = '\0'; // works when putenv() copies nameval *getenv(name) = '\0'; // works when putenv() copies nameval
} }
} }
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#define strcasecmp _stricmp #define strcasecmp _stricmp
......
...@@ -1098,7 +1098,8 @@ TEST(DeprecatedFunctionsTest, AppendFlagsIntoFile) { ...@@ -1098,7 +1098,8 @@ TEST(DeprecatedFunctionsTest, AppendFlagsIntoFile) {
const bool r = AppendFlagsIntoFile(filename, "not the real argv0"); const bool r = AppendFlagsIntoFile(filename, "not the real argv0");
EXPECT_TRUE(r); EXPECT_TRUE(r);
FILE* fp = fopen(filename.c_str(), "r"); FILE* fp;
EXPECT_EQ(0, SafeFOpen(&fp, filename.c_str(), "r"));
EXPECT_TRUE(fp != NULL); EXPECT_TRUE(fp != NULL);
char line[8192]; char line[8192];
EXPECT_TRUE(fgets(line, sizeof(line)-1, fp) != NULL); // get the first line EXPECT_TRUE(fgets(line, sizeof(line)-1, fp) != NULL); // get the first line
...@@ -1134,7 +1135,8 @@ TEST(DeprecatedFunctionsTest, ReadFromFlagsFile) { ...@@ -1134,7 +1135,8 @@ TEST(DeprecatedFunctionsTest, ReadFromFlagsFile) {
TEST(DeprecatedFunctionsTest, ReadFromFlagsFileFailure) { TEST(DeprecatedFunctionsTest, ReadFromFlagsFileFailure) {
FLAGS_test_int32 = -20; FLAGS_test_int32 = -20;
string filename(TmpFile("flagfile3")); string filename(TmpFile("flagfile3"));
FILE* fp = fopen(filename.c_str(), "w"); FILE* fp;
EXPECT_EQ(0, SafeFOpen(&fp, filename.c_str(), "w"));
EXPECT_TRUE(fp != NULL); EXPECT_TRUE(fp != NULL);
// Note the error in the bool assignment below... // Note the error in the bool assignment below...
fprintf(fp, "%s\n--test_int32=-21\n--test_bool=not_a_bool!\n", GetArgv0()); fprintf(fp, "%s\n--test_int32=-21\n--test_bool=not_a_bool!\n", GetArgv0());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment