diff --git a/CMakeLists.txt b/CMakeLists.txt index 054539b4f7..35e50e0c79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ endif () set(CMAKE_VERBOSE_MAKEFILE ON) if (UNIX) # Linux and OSX - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -std=gnu99 -g -fPIC -Werror -Wno-error=deprecated-declarations ${MOCK_OBJECT_WRAPPER_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -std=gnu99 -g -fPIC -Werror -Wno-error=deprecated-declarations -D_LARGEFILE64_SOURCE ${MOCK_OBJECT_WRAPPER_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -std=gnu++11 -fPIC -Werror -Wno-error=deprecated-declarations ${MOCK_OBJECT_WRAPPER_FLAGS}") else() # Windows diff --git a/cpp/FileTransferAgent.cpp b/cpp/FileTransferAgent.cpp index 0323874b1b..223bcf6809 100755 --- a/cpp/FileTransferAgent.cpp +++ b/cpp/FileTransferAgent.cpp @@ -829,6 +829,8 @@ RemoteStorageRequestOutcome Snowflake::Client::FileTransferAgent::downloadSingle FileMetadata *fileMetadata, size_t resultIndex) { + char strerr_buf[SF_ERROR_BUFSIZE]; + fileMetadata->destPath = std::string(response.localLocation) + PATH_SEP + fileMetadata->destFileName; std::string destPathPlatform = m_stmtPutGet->UTF8ToPlatformString(fileMetadata->destPath); @@ -847,20 +849,18 @@ RemoteStorageRequestOutcome Snowflake::Client::FileTransferAgent::downloadSingle } catch (...) { std::string err = "Could not open file " + fileMetadata->destPath + " to downoad"; - char* str_error = sf_strerror(errno); + char* str_error = sf_strerror_s(errno, strerr_buf, sizeof(strerr_buf)); CXX_LOG_DEBUG("Could not open file %s to downoad: %s", fileMetadata->destPath.c_str(), str_error); - sf_free_s(str_error); m_executionResults->SetTransferOutCome(outcome, resultIndex); break; } if (!dstFile.is_open()) { std::string err = "Could not open file " + fileMetadata->destPath + " to downoad"; - char* str_error = sf_strerror(errno); + char* str_error = sf_strerror_s(errno, strerr_buf, sizeof(strerr_buf)); CXX_LOG_DEBUG("Could not open file %s to downoad: %s", fileMetadata->destPath.c_str(), str_error); - sf_free_s(str_error); m_executionResults->SetTransferOutCome(outcome, resultIndex); break; } diff --git a/cpp/SnowflakeAzureClient.cpp b/cpp/SnowflakeAzureClient.cpp index 2db03df4f6..b4128eedba 100755 --- a/cpp/SnowflakeAzureClient.cpp +++ b/cpp/SnowflakeAzureClient.cpp @@ -61,17 +61,16 @@ SnowflakeAzureClient::SnowflakeAzureClient(StageInfo *stageInfo, CXX_LOG_TRACE("ca bundle file from SF_GLOBAL_CA_BUNDLE_FILE *%s*", caBundleFile); } if( caBundleFile[0] == 0 ) { - char* capath = sf_getenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE"); + char capath_buf[MAX_PATH + 2]; + char* capath = sf_getenv_s("SNOWFLAKE_TEST_CA_BUNDLE_FILE", capath_buf, sizeof(capath_buf)); if (capath) { if (strlen(capath) > MAX_PATH - 1) { - sf_free_s(capath); throw SnowflakeTransferException(TransferError::INTERNAL_ERROR, "CA bundle file path too long."); } if (!sb_strcpy(caBundleFile, (size_t)MAX_PATH, capath)) { caBundleFile[0] = 0; } - sf_free_s(capath); CXX_LOG_TRACE("ca bundle file from SNOWFLAKE_TEST_CA_BUNDLE_FILE *%s*", caBundleFile); } } diff --git a/cpp/logger/SFLogger.cpp b/cpp/logger/SFLogger.cpp index e71b5cbcb9..548df6c75b 100644 --- a/cpp/logger/SFLogger.cpp +++ b/cpp/logger/SFLogger.cpp @@ -21,7 +21,7 @@ Snowflake::Client::ISFLogger * Snowflake::Client::SFLogger::getExternalLogger() void log_masked_va_list(FILE* fp, const char *fmt, va_list args) { std::string maskedMsg = Snowflake::Client::SFLogger::getMaskedMsgVA(fmt, args); - fprintf(fp, "%s", maskedMsg.c_str()); + sb_fprintf(fp, "%s", maskedMsg.c_str()); } std::string Snowflake::Client::SFLogger::getMaskedMsg(const char* fmt, ...) diff --git a/cpp/util/Proxy.cpp b/cpp/util/Proxy.cpp index cbf629b1de..8c8013d952 100644 --- a/cpp/util/Proxy.cpp +++ b/cpp/util/Proxy.cpp @@ -7,14 +7,14 @@ #include "snowflake/platform.h" namespace { - char* get_env_or(const char* name) { - return sf_getenv(name); + char* get_env_or(char* outbuf, size_t bufsize, const char* name) { + return sf_getenv_s(name, outbuf, bufsize); } template - char* get_env_or(const char* prime, Args... fallback) + char* get_env_or(char *outbuf, size_t bufsize, const char* prime, Args... fallback) { - char* value = get_env_or(prime); - return value ? value : get_env_or(fallback...); + char* value = get_env_or(outbuf, bufsize, prime); + return value ? value : get_env_or(outbuf, bufsize, fallback...); } } @@ -82,18 +82,17 @@ void Snowflake::Client::Util::Proxy::clearPwd() { } void Snowflake::Client::Util::Proxy::setProxyFromEnv() { - char* env_value = get_env_or("all_proxy", "https_proxy", "http_proxy"); + char valbuf[1024]; + char* env_value = get_env_or(valbuf, sizeof(valbuf), "all_proxy", "https_proxy", "http_proxy"); if (env_value != nullptr) { std::string proxy(env_value); - sf_free_s(env_value); stringToProxyParts(proxy); } // Get noproxy string - env_value = get_env_or("no_proxy", "NO_PROXY"); + env_value = get_env_or(valbuf, sizeof(valbuf), "no_proxy", "NO_PROXY"); if (env_value != nullptr) { m_noProxy = env_value; - sf_free_s(env_value); } } diff --git a/cpp/util/ThreadPool.hpp b/cpp/util/ThreadPool.hpp index 41c8ecd972..806fc0dd5c 100755 --- a/cpp/util/ThreadPool.hpp +++ b/cpp/util/ThreadPool.hpp @@ -155,7 +155,8 @@ class ThreadPool { int err = pthread_key_create(&key, NULL); if (err) { - CXX_LOG_ERROR("Thread pool creating key failed with error: %s", strerror(err)); + char strerrbuf[SF_ERROR_BUFSIZE]; + CXX_LOG_ERROR("Thread pool creating key failed with error: %s", sf_strerror_s(err, strerrbuf, sizeof(strerrbuf))); throw SnowflakeTransferException(TransferError::INTERNAL_ERROR, "Thread context fail to initialize"); } diff --git a/include/snowflake/Simba_CRTFunctionSafe.h b/include/snowflake/Simba_CRTFunctionSafe.h index d529b338b0..40891141dc 100644 --- a/include/snowflake/Simba_CRTFunctionSafe.h +++ b/include/snowflake/Simba_CRTFunctionSafe.h @@ -1,10 +1,6 @@ -// ================================================================================================= -/// @file Simba_CRTFunctionSafe.h -/// -/// C Run-Time library functions' definitions for cross platform use. -/// -/// Copyright (C) 2019 Simba Technologies Incorporated. -// ================================================================================================= +/* + * Copyright (c) 2019-2024 Snowflake Computing, Inc. All rights reserved. + */ #ifndef _SIMBA_CRTFUNCTIONSAFE_H_ #define _SIMBA_CRTFUNCTIONSAFE_H_ @@ -21,186 +17,271 @@ extern "C" { #endif -#ifndef STDCALL - // match snowflake define in platform.h - #ifdef _WIN32 - #define STDCALL __stdcall - #else - #define STDCALL - #endif -#endif - -extern char* STDCALL sf_getenv(const char *name); -extern char* STDCALL sf_strerror(int); +#ifndef STDCALL + // match snowflake define in platform.h + #ifdef _WIN32 + #define STDCALL __stdcall + #else + #define STDCALL + #endif +#endif + +// Defined for #pragma warning messages. +#define MACRO_TO_STRING2(x) #x +#define MACRO_TO_STRING(x) MACRO_TO_STRING2(x) -#if defined(WIN32) || defined(_WIN64) // For Windows +#if defined(_MSC_VER) +#define SF_MACRO_DEPRECATED_WARNING(MSG) __pragma(message ( __FILE__ "(" MACRO_TO_STRING(__LINE__) ") : warning C4996: " MSG)) +#else +#define SF_MACRO_DEPRECATED_WARNING(MSG) _Pragma(MACRO_TO_STRING(GCC warning MSG)) +#endif - #define sf_free_s(x) free(x) +// sf_getenv and sf_strerror is unsafe and deprecated. +// Please change to use sf_getenv_s and sf_strerror_s. +#define sf_getenv SF_MACRO_DEPRECATED_WARNING("sf_getenv is deprecated, please use sf_getenv_s instead.") getenv +#define sf_strerror SF_MACRO_DEPRECATED_WARNING("sf_strerror is deprecated, please use sf_strerror_s instead.") strerror +// sf_free_s is deprecated. It does nothing and should not be called anymore. +#define sf_free_s SF_MACRO_DEPRECATED_WARNING("sf_free_s is deprecated and it does nothing.") - /// @brief Copy a string. - /// + /// @brief Copy bytes between buffers. + /// + /// @param out_dest Destination buffer. (NOT OWN) + /// @param in_destSize Size of the destination buffer. + /// @param in_src Buffer to copy from. (NOT OWN) + /// @param in_sizeToCopy Number of bytes to copy. + /// + /// @return A pointer to destination; NULL if an error occurred. (NOT OWN) + static inline void* sb_memcpy( + void* out_dest, + size_t in_destSize, + const void* in_src, + size_t in_sizeToCopy) + { +#if defined(_WIN32) || defined(_WIN64) + if (0 == memcpy_s(out_dest, in_destSize, in_src, in_sizeToCopy)) + { + return out_dest; + } + return NULL; +#else + if (in_sizeToCopy > in_destSize) + { + return NULL; + } + return memcpy(out_dest, in_src, in_sizeToCopy); +#endif + } + + // helper function for sb_strcpy, sb_strncpy and sbcat on non-Windows + static inline char* sb_copy(void* dst, size_t dstsize, char const* src, long long srclen) + { + const size_t copyLen = (srclen < 0) ? strlen(src) + 1 : srclen; + + //NOTE: this copies the terminul: + return (char*)sb_memcpy(dst, dstsize, src, copyLen); + } + + // helper function for sb_strcat and sb_strncat + static inline char* sb_cat(char* dst, size_t dstsize, char const* src, size_t srclen) + { + size_t dstlen = strlen(dst); + return dstsize < dstlen ? + NULL : + sb_copy(dst + dstlen, dstsize - dstlen, + src, srclen < 0 ? strlen(src) + 1 : srclen); + } + +/// @brief Copy a string. + /// /// @param out_dest Destination string buffer. (NOT OWN) /// @param in_destSize Size of the destination string buffer. /// @param in_src Null-terminated source string buffer. (NOT OWN) - /// + /// /// @return The destination string; NULL if an error occurred. (NOT OWN) - inline char* sb_strcpy( + static inline char* sb_strcpy( char* out_dest, size_t in_destSize, const char* in_src) { +#if defined(_WIN32) || defined(_WIN64) if (0 == strcpy_s(out_dest, in_destSize, in_src)) { return out_dest; } return NULL; +#else + return sb_copy(out_dest, in_destSize, in_src, -1); +#endif } /// @brief Copy characters of one string to another. /// /// @param out_dest Destination string. (NOT OWN) - /// @param in_destSize The size of the destination string, in characters. + /// @param in_destSize The size of the destination string, in characters. /// @param in_src Source string. (NOT OWN) /// @param in_sizeToCopy Number of characters to be copied. - /// + /// /// @return The destination string; NULL if a truncation or error occurred. (NOT OWN) - inline char* sb_strncpy( + static inline char* sb_strncpy( char* out_dest, size_t in_destSize, const char* in_src, size_t in_sizeToCopy) { +#if defined(_WIN32) || defined(_WIN64) if (0 == strncpy_s(out_dest, in_destSize, in_src, in_sizeToCopy)) { return out_dest; } return NULL; +#else + return sb_copy(out_dest, in_destSize, in_src, in_sizeToCopy); +#endif } /// @brief Append to a string. - /// + /// /// @param out_dest Destination string to append to. (NOT OWN) /// @param in_destSize Size of the destination string buffer. /// @param in_src Null-terminated source string buffer. (NOT OWN) - /// + /// /// @return The destination string; NULL if an error occurred. (NOT OWN) - inline char* sb_strcat( + static inline char* sb_strcat( char* out_dest, size_t in_destSize, const char* in_src) { +#if defined(_WIN32) || defined(_WIN64) if (0 == strcat_s(out_dest, in_destSize, in_src)) { return out_dest; } return NULL; +#else + return sb_cat(out_dest, in_destSize, in_src, -1); +#endif } /// @brief Append characters of one string to another. /// /// @param out_dest Destination string to append to. (NOT OWN) - /// @param in_destSize The size of the destination string buffer, in characters. + /// @param in_destSize The size of the destination string buffer, in characters. /// @param in_src Source string. (NOT OWN) /// @param in_sizeToCopy Number of characters to be copied. - /// + /// /// @return The destination string; NULL if a truncation or error occurred. (NOT OWN) - inline char* sb_strncat( + static inline char* sb_strncat( char* out_dest, size_t in_destSize, const char* in_src, size_t in_sizeToCopy) { +#if defined(_WIN32) || defined(_WIN64) if (0 == strncat_s(out_dest, in_destSize, in_src, in_sizeToCopy)) { return out_dest; } return NULL; - } - - /// @brief Copy bytes between buffers. - /// - /// @param out_dest Destination buffer. (NOT OWN) - /// @param in_destSize Size of the destination buffer. - /// @param in_src Buffer to copy from. (NOT OWN) - /// @param in_sizeToCopy Number of bytes to copy. - /// - /// @return A pointer to destination; NULL if an error occurred. (NOT OWN) - inline void* sb_memcpy( - void* out_dest, - size_t in_destSize, - const void* in_src, - size_t in_sizeToCopy) - { - if (0 == memcpy_s(out_dest, in_destSize, in_src, in_sizeToCopy)) - { - return out_dest; - } - return NULL; +#else + return sb_cat(out_dest, in_destSize, in_src, in_sizeToCopy); +#endif } /// @brief Write formatted output using a pointer to a list of arguments. - /// - /// Note: To ensure that there is room for the terminating null, be sure that in_sizeToWrite is + /// + /// Note: To ensure that there is room for the terminating null, be sure that in_sizeToWrite is /// strictly less than in_sizeOfBuffer. - /// + /// /// @param out_buffer Storage location for output. (NOT OWN) - /// @param in_sizeOfBuffer Size of buffer in characters. - /// @param in_sizeToWrite Maximum number of characters to write (not including the + /// @param in_sizeOfBuffer Size of buffer in characters. + /// @param in_sizeToWrite Maximum number of characters to write (not including the /// terminating null). /// @param in_format Format control string. (NOT OWN) /// @param in_argPtr Pointer to list of arguments. - /// - /// @return The number of bytes written to the buffer, not counting the terminating null + /// + /// @return The number of bytes written to the buffer, not counting the terminating null /// character; -1 if the truncation or error occurred. - inline int sb_vsnprintf( + static inline int sb_vsnprintf( char* out_buffer, size_t in_sizeOfBuffer, size_t in_sizeToWrite, const char* in_format, va_list in_argPtr) { - if (in_sizeToWrite >= in_sizeOfBuffer) return -1; - - return _vsnprintf_s(out_buffer, in_sizeOfBuffer, _TRUNCATE, in_format, in_argPtr); +#if defined(_WIN32) || defined(_WIN64) + int ret = _vsnprintf_s(out_buffer, in_sizeOfBuffer, _TRUNCATE, in_format, in_argPtr); +#else + int ret = vsnprintf(out_buffer, in_sizeToWrite + 1, in_format, in_argPtr); + if ((size_t)ret > in_sizeToWrite) + { + ret = -1; + } +#endif + return ret; } - /// @brief Write formatted data to a string. - /// + /// @brief Write formatted data to a string. + /// /// @param out_buffer Storage location for output. (NOT OWN) - /// @param in_sizeOfBuffer Size of buffer in characters. + /// @param in_sizeOfBuffer Size of buffer in characters. /// @param in_format Format control string. (NOT OWN) /// @param ... Optional arguments for printf style conversions. - /// - /// @return The number of bytes written to the buffer, not counting the terminating null + /// + /// @return The number of bytes written to the buffer, not counting the terminating null /// character; -1 if an error occurred. - inline int sb_sprintf( + static inline int sb_sprintf( char* out_buffer, size_t in_sizeOfBuffer, const char* in_format, ...) { - if (!in_sizeOfBuffer) return -1; + va_list ap; + va_start(ap, in_format); + const int ret = sb_vsnprintf(out_buffer, in_sizeOfBuffer, in_sizeOfBuffer - 1, in_format, ap); + va_end(ap); - va_list formatParams; - va_start(formatParams, in_format); - int bytesWritten = sb_vsnprintf(out_buffer, in_sizeOfBuffer, in_sizeOfBuffer - 1, in_format, formatParams); - va_end(formatParams); + return ret; + } + + /// @brief Write formatted data to a string. + /// + /// @param out_buffer Storage location for output. (NOT OWN) + /// @param in_sizeOfBuffer Size of buffer in characters. + /// @param in_sizeToWrite Maximum number of characters to write (not including the + /// terminating null). + /// @param in_format Format control string. (NOT OWN) + /// @param ... Optional arguments for printf style conversions. + /// + /// @return The number of bytes written to the buffer, not counting the terminating null + /// character; -1 if an error occurred. + static inline int sb_snprintf( + char* out_buffer, + size_t in_sizeOfBuffer, + size_t in_sizeToWrite, + const char* in_format, + ...) + { + va_list ap; + va_start(ap, in_format); + const int ret = sb_vsnprintf(out_buffer, in_sizeOfBuffer, in_sizeToWrite, in_format, ap); + va_end(ap); - return bytesWritten; + return ret; } - /// @brief Reads formatted data from a string. - /// - /// Note: A buffer size parameter is required when you use the type field characters - /// c, C, s, S, or string control sets that are enclosed in []. + /// @brief Reads formatted data from a string. + /// + /// Note: A buffer size parameter is required when you use the type field characters + /// c, C, s, S, or string control sets that are enclosed in []. /// /// @param in_buffer Stored data. (NOT OWN) /// @param in_format Format control string. (NOT OWN) /// @param ... Optional arguments. - /// + /// /// @return The number of fields that are successfully converted and assigned; /// -1 if an error occurred. - inline int sb_sscanf( +#if defined(_WIN32) || defined(_WIN64) + static inline int sb_sscanf( const char* in_buffer, const char* in_format, ...) @@ -212,217 +293,83 @@ extern char* STDCALL sf_strerror(int); return ret; } +#else +#define sb_sscanf sscanf +#endif - /// @brief Write formatted string to a FILE*. (See the standard C fprintf for details). - /// + /// @brief Write formatted string to a FILE* using a pointer to a list of arguments. + /// /// @param in_stream Stream to write to. (NOT OWN) /// @param in_format Format control string. (NOT OWN) - /// - /// @return The number of bytes written to the stream, or a negative value if an error occurred. - static inline int sb_fprintf(FILE* in_stream, const char* in_format, ...) - { - va_list vlist; - va_start(vlist, in_format); - int bytesWritten = vfprintf_s(in_stream, in_format, vlist); - va_end(vlist); - - return bytesWritten; - } - - - /// @brief Write formatted string to a stdout*. (See the standard C fprintf for details). - /// - /// @param in_format Format control string. (NOT OWN) - /// - /// @return The number of bytes written to the stream, or a negative value if an error occurred. - static inline int sb_printf(const char* in_format, ...) - { - va_list vlist; - va_start(vlist, in_format); - int bytesWritten = vfprintf_s(stdout, in_format, vlist); - va_end(vlist); - - return bytesWritten; - } - - - #define sb_getenv sf_getenv - #define sb_strerror sf_strerror - - -#else // For all other platforms except Windows - - #define sf_free_s(x) - - /// @brief Copy a string. - /// - /// @param out_dest Destination string buffer. (NOT OWN) - /// @param in_destSize Size of the destination string buffer. - /// @param in_src Null-terminated source string buffer. (NOT OWN) - /// - /// @return The destination string; NULL if an error occurred. (NOT OWN) - static inline char* sb_strcpy( - char* out_dest, - size_t in_destSize, - const char* in_src) - { - return strcpy(out_dest, in_src); - } - - /// @brief Copy characters of one string to another. + /// @param in_argPtr Pointer to list of arguments. /// - /// @param out_dest Destination string. (NOT OWN) - /// @param in_destSize The size of the destination string, in characters. - /// @param in_src Source string. (NOT OWN) - /// @param in_sizeToCopy Number of characters to be copied. - /// - /// @return The destination string; NULL if a truncation or error occurred. (NOT OWN) - static inline char* sb_strncpy( - char* out_dest, - size_t in_destSize, - const char* in_src, - size_t in_sizeToCopy) - { - return strncpy(out_dest, in_src, in_sizeToCopy); - } - - /// @brief Append to a string. - /// - /// @param out_dest Destination string to append to. (NOT OWN) - /// @param in_destSize Size of the destination string buffer. - /// @param in_src Null-terminated source string buffer. (NOT OWN) - /// - /// @return The destination string; NULL if an error occurred. (NOT OWN) - static inline char* sb_strcat( - char* out_dest, - size_t in_destSize, - const char* in_src) + /// @return The number of bytes written to the stream, not counting the terminating null + /// character; -1 if the truncation or error occurred. + static inline int sb_vfprintf(FILE* in_stream, const char* in_format, va_list in_argPtr) { - return strcat(out_dest, in_src); + return +#if defined(_WIN32) || defined(_WIN64) + vfprintf_s( +#else + vfprintf( +#endif + in_stream, + in_format, + in_argPtr); } - /// @brief Append characters of one string to another. + /// @brief Write formatted string to a FILE*. (See the standard C fprintf for details). /// - /// @param out_dest Destination string to append to. (NOT OWN) - /// @param in_destSize The size of the destination string buffer, in characters. - /// @param in_src Source string. (NOT OWN) - /// @param in_sizeToCopy Number of characters to be copied. - /// - /// @return The destination string; NULL if a truncation or error occurred. (NOT OWN) - static inline char* sb_strncat( - char* out_dest, - size_t in_destSize, - const char* in_src, - size_t in_sizeToCopy) - { - return strncat(out_dest, in_src, in_sizeToCopy); - } - - /// @brief Copy bytes between buffers. - /// - /// @param out_dest Destination buffer. (NOT OWN) - /// @param in_destSize Size of the destination buffer. - /// @param in_src Buffer to copy from. (NOT OWN) - /// @param in_sizeToCopy Number of bytes to copy. - /// - /// @return A pointer to destination; NULL if an error occurred. (NOT OWN) - static inline void* sb_memcpy( - void* out_dest, - size_t in_destSize, - const void* in_src, - size_t in_sizeToCopy) - { - return memcpy(out_dest, in_src, in_sizeToCopy); - } - - /// @brief Write formatted output using a pointer to a list of arguments. - /// - /// Note: To ensure that there is room for the terminating null, be sure that in_sizeToWrite is - /// strictly less than in_sizeOfBuffer. - /// - /// @param out_buffer Storage location for output. (NOT OWN) - /// @param in_sizeOfBuffer Size of buffer in characters. - /// @param in_sizeToWrite Maximum number of characters to write (not including the - /// terminating null). + /// @param in_stream Stream to write to. (NOT OWN) /// @param in_format Format control string. (NOT OWN) - /// @param in_argPtr Pointer to list of arguments. - /// - /// @return The number of bytes written to the buffer, not counting the terminating null - /// character; -1 if the truncation or error occurred. - static inline int sb_vsnprintf( - char* out_buffer, - size_t in_sizeOfBuffer, - size_t in_sizeToWrite, - const char* in_format, - va_list in_argPtr) + /// + /// @return The number of bytes written to the stream, or a negative value if an error occurred. + static inline int sb_fprintf(FILE* in_stream, const char* in_format, ...) { - // vsnprintf takes the size including terminating null while in_sizeToWrite does not - // include terminating null. - if (in_sizeToWrite >= in_sizeOfBuffer) return -1; - - int ret = vsnprintf(out_buffer, in_sizeToWrite + 1, in_format, in_argPtr); - if ((ret < 0) || ((size_t)ret > in_sizeToWrite)) return -1; + va_list ap; + va_start(ap, in_format); + const int ret = sb_vfprintf(in_stream, in_format, ap); + va_end(ap); return ret; } - /// @brief Write formatted data to a string. - /// - /// @param out_buffer Storage location for output. (NOT OWN) - /// @param in_sizeOfBuffer Size of buffer in characters. + /// @brief Write formatted string to a stdout*. (See the standard C fprintf for details). + /// /// @param in_format Format control string. (NOT OWN) - /// @param ... Optional arguments for printf style conversions. - /// - /// @return The number of bytes written to the buffer, not counting the terminating null - /// character; -1 if an error occurred. - static inline int sb_sprintf( - char* out_buffer, - size_t in_sizeOfBuffer, - const char* in_format, - ...) + /// + /// @return The number of bytes written to the stream, or a negative value if an error occurred. + static inline int sb_printf(const char* in_format, ...) { - va_list formatParams; - va_start(formatParams, in_format); - int bytesWritten = sb_vsnprintf(out_buffer, in_sizeOfBuffer, in_sizeOfBuffer - 1, in_format, formatParams); - va_end(formatParams); + va_list ap; + va_start(ap, in_format); + const int ret = sb_vfprintf(stdout, in_format, ap); + va_end(ap); - return bytesWritten; + return ret; } -#define sb_sscanf sscanf -#define sb_fprintf fprintf -#define sb_printf printf -#define sb_strerror strerror - -#define sb_getenv getenv - -#endif - /// @brief Open a file. - /// + /// /// @param out_file A pointer to the file pointer that will receive the pointer to the /// opened file. (NOT OWN) /// @param in_filename The name of the file to open. (NOT OWN) /// @param in_mode Type of access permitted. (NOT OWN) - /// + /// /// @return A pointer to the opened file; a NULL pointer if an error occurred. (OWN) static inline FILE* sb_fopen(FILE** out_file, const char* in_filename, const char* in_mode) { -#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) - // to simulate fopen, *out_file is guaranteed to be set, fopen_s don't change out_file on error +#if defined(_WIN32) || defined(_WIN64) return fopen_s(out_file, in_filename, in_mode) ? (*out_file = NULL) : *out_file; -#else +#elif defined(__APPLE__) return *out_file = fopen(in_filename, in_mode); +#else + return *out_file = fopen64(in_filename, in_mode); #endif } -#define sb_free_s sf_free_s - - #ifdef __cplusplus } #endif - - #endif diff --git a/include/snowflake/platform.h b/include/snowflake/platform.h index ebc8c9689c..d5e120bbaa 100755 --- a/include/snowflake/platform.h +++ b/include/snowflake/platform.h @@ -56,21 +56,14 @@ void STDCALL sf_tzset(void); int STDCALL sf_setenv(const char *name, const char *value); -/* on Windows, this function allocate new memory, caller should free it */ -char *STDCALL sf_getenv(const char *name); +char *STDCALL sf_getenv_s(const char *name, char *outbuf, size_t bufsize); int STDCALL sf_unsetenv(const char *name); int STDCALL sf_mkdir(const char *path); -/* on Windows, this function allocate new memory, caller should free it */ -char* STDCALL sf_strerror(int errnum); - -#ifdef _WIN32 -#define sf_free_s(x) free(x) -#else -#define sf_free_s(x) -#endif +#define SF_ERROR_BUFSIZE 1024 +char* STDCALL sf_strerror_s(int errnum, char* outbuf, size_t bufsize); int STDCALL _thread_init(SF_THREAD_HANDLE *thread, void *(*proc)(void *), void *arg); diff --git a/lib/client.c b/lib/client.c index c2aab8b0bf..3f87cff3f3 100644 --- a/lib/client.c +++ b/lib/client.c @@ -308,19 +308,22 @@ static sf_bool STDCALL log_init(const char *log_path, SF_LOG_LEVEL log_level) { time_info = localtime(¤t_time); strftime(time_str, sizeof(time_str), "%Y%m%d%H%M%S", time_info); const char *sf_log_path; + char log_path_buf[MAX_PATH]; const char *sf_log_level_str; + char log_level_buf[64]; SF_LOG_LEVEL sf_log_level = log_level; + char strerror_buf[SF_ERROR_BUFSIZE]; size_t log_path_size = 1; //Start with 1 to include null terminator log_path_size += strlen(time_str); /* The environment variables takes precedence over the specified parameters */ - sf_log_path = sf_getenv("SNOWFLAKE_LOG_PATH"); + sf_log_path = sf_getenv_s("SNOWFLAKE_LOG_PATH", log_path_buf, sizeof(log_path_buf)); if (sf_log_path == NULL && log_path) { sf_log_path = log_path; } - sf_log_level_str = sf_getenv("SNOWFLAKE_LOG_LEVEL"); + sf_log_level_str = sf_getenv_s("SNOWFLAKE_LOG_LEVEL", log_level_buf, sizeof(log_level_buf)); if (sf_log_level_str != NULL) { sf_log_level = log_from_str_to_level(sf_log_level_str); } @@ -349,9 +352,8 @@ static sf_bool STDCALL log_init(const char *log_path, SF_LOG_LEVEL log_level) { if (LOG_PATH != NULL) { // Create log file path (if it already doesn't exist) if (mkpath(LOG_PATH) == -1) { - char* str_error = sf_strerror(errno); + char* str_error = sf_strerror_s(errno, strerror_buf, sizeof(strerror_buf)); sb_fprintf(stderr, "Error creating log directory. Error code: %s\n", str_error); - sf_free_s(str_error); goto cleanup; } // Set the log path only, the log file will be created when actual log output is needed. @@ -365,10 +367,6 @@ static sf_bool STDCALL log_init(const char *log_path, SF_LOG_LEVEL log_level) { ret = SF_BOOLEAN_TRUE; cleanup: - if (sf_log_path != log_path) { - sf_free_s((char*) sf_log_path); - } - sf_free_s((char*) sf_log_level_str); return ret; } @@ -3092,7 +3090,8 @@ SF_STATUS STDCALL snowflake_timestamp_from_epoch_seconds(SF_TIMESTAMP *ts, const * so that localtime_tz honors it. */ _mutex_lock(&gmlocaltime_lock); - const char *prev_tz_ptr = sf_getenv("TZ"); + char tzbuf[128]; + const char *prev_tz_ptr = sf_getenv_s("TZ", tzbuf, sizeof(tzbuf)); sf_setenv("TZ", tzptr); sf_tzset(); sec += tzoffset * 60 * 2; /* adjust for TIMESTAMP_TZ */ diff --git a/lib/logger.c b/lib/logger.c index 346d111a63..dc339ca5da 100644 --- a/lib/logger.c +++ b/lib/logger.c @@ -109,6 +109,7 @@ log_log_va_list(int level, const char *file, int line, const char *ns, return; } + char strerr_buf[SF_ERROR_BUFSIZE]; char tsbuf[50]; /* timestamp buffer*/ sf_log_timestamp(tsbuf, sizeof(tsbuf)); @@ -147,11 +148,10 @@ log_log_va_list(int level, const char *file, int line, const char *ns, { if (sb_fopen(&L.fp, L.path, "w+") == NULL) { - char* str_error = sf_strerror(errno); + char* str_error = sf_strerror_s(errno, strerr_buf, sizeof(strerr_buf)); sb_fprintf(stderr, "Error opening file from file path: %s\nError code: %s\n", L.path, str_error); - sf_free_s(str_error); L.path = NULL; } } diff --git a/lib/platform.c b/lib/platform.c index 0ab9848cba..e534008286 100755 --- a/lib/platform.c +++ b/lib/platform.c @@ -192,7 +192,8 @@ struct tm* sfchrono_gmtime(const time_t *timep, struct tm *tm) struct tm* sfchrono_localtime(const time_t *timep, struct tm *tm) { time_t t = *timep; - char * tzptr = sf_getenv("TZ"); + char tzbuf[128]; + char * tzptr = sf_getenv_s("TZ", tzbuf, sizeof(tzbuf)); // use TZ environemt variable setting for timestamp_tz if (tzptr && (strlen(tzptr) >= 3) && (strncmp(tzptr, "UTC", 3) == 0)) @@ -267,13 +268,19 @@ int STDCALL sf_setenv(const char *name, const char *value) { #endif } -char * STDCALL sf_getenv(const char *name) { +char * STDCALL sf_getenv_s(const char *name, char *outbuf, size_t bufsize) { #ifdef _WIN32 - char* result = NULL; - return _dupenv_s(&result, NULL, name) ? NULL : result; -# else - return getenv(name); -# endif + size_t len; + return getenv_s(&len, outbuf, bufsize, name) ? NULL : outbuf; +#else + char* envval = getenv(name); + if (!envval) + { + return NULL; + } + + return sb_strcpy(outbuf, bufsize, envval); +#endif } int STDCALL sf_unsetenv(const char *name) { @@ -292,16 +299,14 @@ int STDCALL sf_mkdir(const char *path) { #endif } -char* STDCALL sf_strerror(int in_errNumber) +char* STDCALL sf_strerror_s(int in_errNumber, char* outbuf, size_t bufsize) { +// return "" in error case. Failing to get error message can be ignored and that +// would be better than possiblly causing crash on callder side. #ifdef _WIN32 - char* buf = (char*)malloc(BUFSIZ); - if (buf && 0 == strerror_s(buf, BUFSIZ, in_errNumber)) - return buf; - free(buf); - return NULL; + return strerror_s(outbuf, bufsize, in_errNumber) ? "" : outbuf; #else - return strerror(in_errNumber); + return strerror_r(in_errNumber, outbuf, bufsize) ? "" : outbuf; #endif } @@ -815,7 +820,9 @@ void STDCALL sf_get_tmp_dir(char * tmpDir) #ifdef _WIN32 GetTempPath(100, tmpDir); #else - const char * tmpEnv = getenv("TMP") ? getenv("TMP") : getenv("TEMP"); + char envbuf[MAX_PATH + 1]; + const char * tmpEnv = sf_getenv_s("TMP", envbuf, sizeof(envbuf)) ? + sf_getenv_s("TMP", envbuf, sizeof(envbuf)) : sf_getenv_s("TEMP", envbuf, sizeof(envbuf)); if (!tmpEnv) { diff --git a/scripts/build_oob.sh b/scripts/build_oob.sh index b04528d5f8..1dc75888ab 100755 --- a/scripts/build_oob.sh +++ b/scripts/build_oob.sh @@ -42,6 +42,7 @@ if [[ "$PLATFORM" == "linux" ]]; then # Linux 64 bit export AR=ar export AROPTIONS=rcs + export CFLAGS="-D_LARGEFILE64_SOURCE" make distclean clean > /dev/null || true make LIB=libtelemetry.a elif [[ "$PLATFORM" == "darwin" ]]; then diff --git a/tests/test_connect.c b/tests/test_connect.c index b97c4c2d69..2b67e40e4b 100644 --- a/tests/test_connect.c +++ b/tests/test_connect.c @@ -194,12 +194,7 @@ void test_connect_with_ocsp_cache_server_on(void **unused) { * in parameter are being used. */ void test_connect_with_proxy(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) - { - // skip the test if the test evironment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; // set invalid proxy in environment variables sf_setenv("https_proxy", "a.b.c"); diff --git a/tests/test_simple_put.cpp b/tests/test_simple_put.cpp index 0812268f99..966fb43508 100755 --- a/tests/test_simple_put.cpp +++ b/tests/test_simple_put.cpp @@ -1262,11 +1262,7 @@ void test_2GBlarge_get(void **unused) void test_simple_put_with_proxy(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test environment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; // set invalid proxy in environment variables sf_setenv("https_proxy", "a.b.c"); @@ -1306,11 +1302,7 @@ void test_simple_put_with_proxy(void **unused) void test_simple_put_with_noproxy(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test evironment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; // set invalid proxy in environment variables sf_setenv("https_proxy", "a.b.c"); @@ -1351,11 +1343,7 @@ void test_simple_put_with_noproxy(void **unused) void test_simple_put_with_proxy_fromenv(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test environment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; // set invalid proxy settings sf_setenv("https_proxy", "a.b.c"); @@ -1402,11 +1390,7 @@ void test_simple_put_with_proxy_fromenv(void **unused) void test_simple_put_with_noproxy_fromenv(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test environment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; // set invalid proxy settings sf_setenv("https_proxy", "a.b.c"); diff --git a/tests/test_unit_azure_client.cpp b/tests/test_unit_azure_client.cpp index fe96e531cc..c016179bbc 100644 --- a/tests/test_unit_azure_client.cpp +++ b/tests/test_unit_azure_client.cpp @@ -179,7 +179,8 @@ void test_azure_empty_cafile_noenv(void ** unused) transferConfig.caBundleFile = cafile; // Modify the environment variable temporarily and restore at the end of test - const char* currentCABundleFile = sf_getenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE"); + char caenvbuf[MAX_PATH]; + const char* currentCABundleFile = sf_getenv_s("SNOWFLAKE_TEST_CA_BUNDLE_FILE", caenvbuf, sizeof(caenvbuf)); if (currentCABundleFile) { hasCAfileEnvChanged = true; @@ -215,7 +216,8 @@ void test_azure_empty_cafile_from_env(void ** unused) transferConfig.caBundleFile = cafile; // Modify the environment variable temporarily and restore at the end of test - const char* currentCABundleFile = sf_getenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE"); + char caenvbuf[MAX_PATH]; + const char* currentCABundleFile = sf_getenv_s("SNOWFLAKE_TEST_CA_BUNDLE_FILE", caenvbuf, sizeof(caenvbuf)); sf_setenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE", "/tmp/cafile/p1.pem"); hasCAfileEnvChanged = true; @@ -248,7 +250,8 @@ void test_azure_empty_cafile_from_global_env(void ** unused) transferConfig.caBundleFile = cafile; // Modify the environment variable temporarily and restore at the end of test - const char* currentCABundleFile = sf_getenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE"); + char caenvbuf[MAX_PATH]; + const char* currentCABundleFile = sf_getenv_s("SNOWFLAKE_TEST_CA_BUNDLE_FILE", caenvbuf, sizeof(caenvbuf)); if (currentCABundleFile) { hasCAfileEnvChanged = true; @@ -281,7 +284,8 @@ void test_azure_cafile_path_too_long_from_env_transferconfig_null(void ** unused std::string cafile(MAX_PATH, 'a'); // Modify the environment variable temporarily and restore at the end of test - const char* currentCABundleFile = sf_getenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE"); + char caenvbuf[MAX_PATH]; + const char* currentCABundleFile = sf_getenv_s("SNOWFLAKE_TEST_CA_BUNDLE_FILE",caenvbuf, sizeof(caenvbuf)); sf_setenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE", cafile.c_str()); hasCAfileEnvChanged = true; @@ -314,7 +318,8 @@ void test_azure_cafile_path_too_long_from_global_env_transferconfig_null(void ** std::string cafile(MAX_PATH, 'a'); // Modify the environment variable temporarily and restore at the end of test - const char* currentCABundleFile = sf_getenv("SNOWFLAKE_TEST_CA_BUNDLE_FILE"); + char caenvbuf[MAX_PATH]; + const char* currentCABundleFile = sf_getenv_s("SNOWFLAKE_TEST_CA_BUNDLE_FILE", caenvbuf, sizeof(caenvbuf)); if (currentCABundleFile) { hasCAfileEnvChanged = true; diff --git a/tests/test_unit_proxy.cpp b/tests/test_unit_proxy.cpp index f53293a0af..6dce6f6b88 100755 --- a/tests/test_unit_proxy.cpp +++ b/tests/test_unit_proxy.cpp @@ -66,11 +66,7 @@ void test_proxy_empty(void **unused) void test_allproxy_noproxy_fromenv(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test environment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; sf_setenv("all_proxy", "https://someuser:somepwd@somewhere.com:5050"); sf_setenv("no_proxy", "proxyserver.com"); @@ -81,11 +77,7 @@ void test_allproxy_noproxy_fromenv(void **unused) void test_httpsproxy_fromenv(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test environment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; sf_setenv("https_proxy", "https://someuser:somepwd@somewhere.com:5050"); test_proxy_parts_equality("", "someuser", "somepwd", "somewhere.com", 5050, Proxy::Protocol::HTTPS, "", true); @@ -94,11 +86,7 @@ void test_httpsproxy_fromenv(void **unused) void test_httpproxy_fromenv(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test environment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; sf_setenv("http_proxy", "http://username:password@proxyserver.company.com:80"); test_proxy_parts_equality("", "username", "password", "proxyserver.company.com", 80, Proxy::Protocol::HTTP, "", true); @@ -107,11 +95,7 @@ void test_httpproxy_fromenv(void **unused) void test_noproxy_fromenv(void **unused) { - if (sf_getenv("all_proxy") || sf_getenv("https_proxy") || - sf_getenv("http_proxy")) { - // skip the test if the test environment uses proxy already - return; - } + SKIP_IF_PROXY_ENV_IS_SET; sf_setenv("NO_PROXY", "proxyserver.company.com"); test_proxy_parts_equality("", "", "", "", 0, Proxy::Protocol::NONE, "proxyserver.company.com", true); diff --git a/tests/utils/test_setup.h b/tests/utils/test_setup.h index 6c46e01218..f0e938c3e2 100644 --- a/tests/utils/test_setup.h +++ b/tests/utils/test_setup.h @@ -20,6 +20,15 @@ extern "C" { #include #include +#define SKIP_IF_PROXY_ENV_IS_SET \ +{ \ + char envbuf[1024]; \ + if (sf_getenv_s("all_proxy", envbuf, sizeof(envbuf)) || sf_getenv_s("https_proxy", envbuf, sizeof(envbuf)) || \ + sf_getenv_s("http_proxy", envbuf, sizeof(envbuf))) { \ + return; \ + } \ +} + void initialize_test(sf_bool debug); SF_STATUS STDCALL enable_arrow_force(SF_CONNECT *sf);