# - Check what flag is needed to enable stack smashing protection # CHECK_STACK_PROTECTOR_COMPILER_FLAG(VARIABLE) # # VARIABLE - variable to store the result # # This actually calls the check_c_source_compiles macro. # See help for CheckCSourceCompiles for a listing of variables # that can modify the build. # Copyright (c) 2006, Alexander Neundorf, # C++ 2011 version Copyright (c) 2011 by David Korth. # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # Based on CHECK_C99_COMPILER_FLAG(). (CheckC99CompilerFlag.cmake) INCLUDE(CheckCSourceCompiles) FUNCTION(CHECK_STACK_PROTECTOR_COMPILER_FLAG _result) UNSET(${_result} PARENT_SCOPE) IF(NOT DEFINED _SYS_STACK_PROTECTOR_COMPILER_FLAG) IF(MSVC) # MSVC 2002 introduced the /GS option. # MSVC 2005+ enables it by default. IF(MSVC_VERSION GREATER 1399) # MSVC 2005+. SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "" CACHE INTERNAL "CFLAG required for stack smashing protection.") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: none, enabled by default") ELSEIF(MSVC_VERSION GREATER 1299) # MSVC 2002 or 2003. SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "/GS" CACHE INTERNAL "CFLAG required for stack smashing protection.") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${_SYS_STACK_PROTECTOR_COMPILER_FLAG}") ELSE() # MSVC 2002 or earlier. SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "" CACHE INTERNAL "CFLAG required for stack smashing protection.") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available") ENDIF() ELSE(MSVC) # gcc-4.1: -fstack-protector, -fstack-protector-all # gcc-4.9: -fstack-protector-strong MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection:") FOREACH(CHECK_STACK_CFLAG "-fstack-protector-strong" "-fstack-protector-all" "-fstack-protector") # CMake doesn't like "+" characters in variable names. STRING(REPLACE "+" "_" CHECK_STACK_CFLAG_VARNAME "CHECK_CFLAG_${CHECK_STACK_CFLAG}") SET(OLD_CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) SET(OLD_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) SET(CMAKE_REQUIRED_DEFINITIONS ${CHECK_STACK_CFLAG}) IF(WIN32) SET(CMAKE_REQUIRED_LIBRARIES kernel32) ELSE(WIN32) SET(CMAKE_REQUIRED_LIBRARIES c) ENDIF(WIN32) # NOTE: We need a function that triggers stack smashing protection # in order to determine if libssp is needed on MinGW-w64. # Based on wrapper functions in c99-compat.msvcrt.h. CHECK_C_SOURCE_COMPILES(" #include #include #ifndef _MSC_VER #define _vsnprintf vsnprintf #endif int C99_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int ret = _vsnprintf(str, size, format, ap); if (ret >= (int)size) { // Make sure the buffer is NULL-terminated. str[size-1] = 0; } else if (ret < 0) { // Make sure the buffer is empty. // MSVCRT *should* do this, but just in case... str[0] = 0; } return ret; } int C99_snprintf(char *str, size_t size, const char *format, ...) { int ret; va_list ap; va_start(ap, format); ret = C99_vsnprintf(str, size, format, ap); va_end(ap); return ret; } int main(int argc, char *argv[]) { char buf[128]; snprintf(buf, sizeof(buf), \"test: %s\", argv[0]); puts(buf); return 0; }" ${CHECK_STACK_CFLAG_VARNAME}) SET(CMAKE_REQUIRED_DEFINITIONS ${OLD_CMAKE_REQUIRED_DEFINITIONS}) SET(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQUIRED_LIBRARIES}) UNSET(OLD_CMAKE_REQUIRED_INCLUDES) UNSET(OLD_CMAKE_REQUIRED_LIBRARIES) IF(${${CHECK_STACK_CFLAG_VARNAME}}) SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "${CHECK_STACK_CFLAG}" CACHE INTERNAL "CFLAG required for stack smashing protection.") BREAK() ENDIF(${${CHECK_STACK_CFLAG_VARNAME}}) ENDFOREACH() IF(_SYS_STACK_PROTECTOR_COMPILER_FLAG) MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${_SYS_STACK_PROTECTOR_COMPILER_FLAG}") ELSE(_SYS_STACK_PROTECTOR_COMPILER_FLAG) SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "" CACHE INTERNAL "CFLAG required for stack smashing protection.") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available") MESSAGE(WARNING "Stack smashing protection is not available.\nPlease check your toolchain installation.") ENDIF(_SYS_STACK_PROTECTOR_COMPILER_FLAG) ENDIF(MSVC) ENDIF(NOT DEFINED _SYS_STACK_PROTECTOR_COMPILER_FLAG) SET(${_result} "${_SYS_STACK_PROTECTOR_COMPILER_FLAG}" PARENT_SCOPE) ENDFUNCTION(CHECK_STACK_PROTECTOR_COMPILER_FLAG)