changeset 1:524cd4908656

Build infrastructure Add hardening flags Add static_check target for flawfinder and cppcheck
author Andre Heinecke <aheinecke@intevation.de>
date Mon, 10 Feb 2014 16:14:55 +0000
parents cb0cde2c5eb9
children cf88cc432b9d
files CMakeLists.txt cmake/GenerateCppcheck.cmake cmake/ParseArguments.cmake
diffstat 3 files changed, 226 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Fri Feb 07 11:41:15 2014 +0000
+++ b/CMakeLists.txt	Mon Feb 10 16:14:55 2014 +0000
@@ -11,7 +11,6 @@
 
 include_directories(${Qt5Widgets_INCLUDE_DIRS})
 add_definitions(${Qt5Widgets_DEFINITIONS})
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
 
 set(M13UI_SOURCES
     ui/main.cpp
@@ -22,6 +21,17 @@
     ui/icons.qrc
 )
 
+# Warn level to be used for privileged parts
+set(WARN_HARDENING_FLAGS " -Wall -Wextra -Wconversion -Wformat-security")
+
+# Hardening flags
+set(HARDENING_FLAGS " -Werror -fstack-protector-all")
+set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wstack-protector")
+set(HARDENING_FLAGS " ${HARDENING_FLAGS} --param ssp-buffer-size=4")
+set(HARDENING_FLAGS " ${HARDENING_FLAGS} -pie -fPIE -ftrapv")
+set(HARDENING_FLAGS " ${HARDENING_FLAGS} -D_FORTIFY_SOURCE=2 -O2")
+set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wl,-z,relro,-z,now")
+
 if(UNIX)
    # See: https://bugreports.qt-project.org/browse/QTBUG-35918
    # XCB_EXTRA_LIBS should be gotten automatically.
@@ -48,10 +58,32 @@
         -lglu32 -lopengl32 -lgdi32 -ljpeg -lpng -lQt5Core -lole32 -luuid -lws2_32
         -ladvapi32 -lshell32 -luser32 -lkernel32 -lz -lsicuin -lsicuuc -lsicudt -lpcre16)
    set(EXTRA_STATIC_LIBS Qt5::QWindowsIntegrationPlugin ${WINDOWS_EXTRA_LIBS})
+
+   set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wl,dynamicbase -Wl,nxcompat")
 endif()
 
 qt5_add_resources(M13UI_SOURCES ${M13UI_RESOURCES})
 
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${HARDENING_FLAGS}")
+
 add_executable(m13ui ${M13UI_SOURCES})
 
 target_link_libraries(m13ui Qt5::Widgets ${EXTRA_STATIC_LIBS})
+
+add_custom_target(static_check)
+
+# CPPCheck
+include(GenerateCppcheck)
+generate_cppcheck(SOURCES ${M13UI_SOURCES} "" "" m13ui)
+add_dependencies(static_check cppcheck)
+
+# FlawFinder
+find_program(FLAWFINDER_PATH flawfinder DOC "flawfinder path")
+if (FLAWFINDER_PATH)
+    add_custom_target(flawfinder COMMENT "FlawFinder" VERBATIM COMMAND ${FLAWFINDER_PATH}
+       ${CMAKE_SOURCE_DIR}/ui
+    )
+    add_dependencies(static_check flawfinder)
+endif (FLAWFINDER_PATH)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/GenerateCppcheck.cmake	Mon Feb 10 16:14:55 2014 +0000
@@ -0,0 +1,141 @@
+# - Generate a cppcheck documentation for a project.
+# The function GENERATE_CPPCHECK is provided to create a "cppcheck" target that
+# performs static code analysis using the cppcheck utility program.
+#
+# GENERATE_CPPCHECK(SOURCES <sources to check...>
+#                   [SUPPRESSION_FILE <file>]
+#                   [ENABLE_IDS <id...>]
+#                   [TARGET_NAME <name>]
+#                   [INCLUDES <dir...>])
+#
+# Generates a target "cppcheck" that executes cppcheck on the specified sources.
+# Sources may either be file names or directories containing files where all
+# C++ files will be parsed automatically. Use directories whenever possible
+# because there is a limitation in arguments to pass to the cppcheck binary.
+# SUPPRESSION_FILE may be give additionally to specify suppressions for#
+# cppcheck. The sources mentioned in the suppression file must be in the same
+# format like given for SOURCES. This means if you specified them relative to
+# CMAKE_CURRENT_SOURCE_DIR, then the same relative paths must be used in the
+# suppression file.
+# ENABLE_IDS allows to specify which additional cppcheck check ids to execute,
+# e.g. all or style. They are combined with AND.
+# With TARGET_NAME a different name for the generated check target can be
+# specified. This is useful if several calles to this function are made in one
+# CMake project, as otherwise the target names collide.
+# Additional include directories for the cppcheck program can be given with
+# INCLUDES.
+#
+# cppcheck will be executed with CMAKE_CURRENT_SOURCE_DIR as working directory.
+#
+# This function can always be called, even if no cppcheck was found. Then no
+# target is created.
+#
+# Copyright (C) 2011 by Johannes Wienke <jwienke at techfak dot uni-bielefeld dot de>
+#
+# This program is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General
+# Public License as published by the Free Software Foundation;
+# either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+
+GET_FILENAME_COMPONENT(GENERATE_CPPCHECK_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+# FIND_PACKAGE(Cppcheck)
+find_program(CPPCHECK_EXECUTABLE
+cppcheck
+)
+
+if(CPPCHECK_EXECUTABLE)
+   set(CPPCHECK_FOUND True)
+endif()
+
+include(ParseArguments)
+
+FUNCTION(GENERATE_CPPCHECK)
+
+    IF(CPPCHECK_FOUND)
+
+       PARSE_ARGUMENTS(ARG "SOURCES;SUPPRESSION_FILE;ENABLE_IDS;TARGET_NAME;INCLUDES" "" ${ARGN})
+
+        SET(TARGET_NAME "cppcheck")
+        SET(TARGET_NAME_SUFFIX "")
+        # parse target name
+        LIST(LENGTH ARG_TARGET_NAME TARGET_NAME_LENGTH)
+        IF(${TARGET_NAME_LENGTH} EQUAL 1)
+            SET(TARGET_NAME ${ARG_TARGET_NAME})
+            SET(TARGET_NAME_SUFFIX "-${ARG_TARGET_NAME}")
+        ENDIF()
+
+        SET(CPPCHECK_CHECKFILE "${CMAKE_BINARY_DIR}/cppcheck-files${TARGET_NAME_SUFFIX}")
+        SET(CPPCHECK_REPORT_FILE "${CMAKE_BINARY_DIR}/cppcheck-report${TARGET_NAME_SUFFIX}.xml")
+        SET(CPPCHECK_WRAPPER_SCRIPT "${CMAKE_BINARY_DIR}/cppcheck${TARGET_NAME_SUFFIX}.cmake")
+
+        # write a list file containing all sources to check for the call to
+        # cppcheck
+        SET(SOURCE_ARGS "")
+        FOREACH(SOURCE ${ARG_SOURCES})
+            SET(SOURCE_ARGS "${SOURCE_ARGS} \"${SOURCE}\"")
+        ENDFOREACH()
+
+        # prepare a cmake wrapper to write the stderr output of cppcheck to
+        # the result file
+
+        # suppression argument
+        LIST(LENGTH ARG_SUPPRESSION_FILE SUPPRESSION_FILE_LENGTH)
+        IF(${SUPPRESSION_FILE_LENGTH} EQUAL 1)
+            GET_FILENAME_COMPONENT(ABS "${ARG_SUPPRESSION_FILE}" ABSOLUTE)
+            MESSAGE(STATUS "Using suppression file ${ABS}")
+            SET(SUPPRESSION_ARGUMENT --suppressions)
+            SET(SUPPRESSION_FILE "\"${ABS}\"")
+        ENDIF()
+
+        # includes
+        SET(INCLUDE_ARGUMENTS "")
+        FOREACH(INCLUDE ${ARG_INCLUDES})
+            SET(INCLUDE_ARGUMENTS "${INCLUDE_ARGUMENTS} \"-I${INCLUDE}\"")
+        ENDFOREACH()
+
+        # enabled ids
+        SET(ID_LIST "")
+        FOREACH(ID ${ARG_ENABLE_IDS})
+            SET(ID_LIST "${ID_LIST},${ID}")
+        ENDFOREACH()
+        IF(ID_LIST)
+            STRING(LENGTH ${ID_LIST} LIST_LENGTH)
+            MATH(EXPR FINAL_LIST_LENGTH "${LIST_LENGTH} - 1")
+            STRING(SUBSTRING ${ID_LIST} 1 ${FINAL_LIST_LENGTH} FINAL_ID_LIST)
+            SET(IDS_ARGUMENT "\"--enable=${FINAL_ID_LIST}\"")
+        ELSE()
+            SET(IDS_ARGUMENT "")
+        ENDIF()
+
+        FILE(WRITE ${CPPCHECK_WRAPPER_SCRIPT}
+"
+EXECUTE_PROCESS(COMMAND \"${CPPCHECK_EXECUTABLE}\" ${INCLUDE_ARGUMENTS} ${SUPPRESSION_ARGUMENT} ${SUPPRESSION_FILE} ${IDS_ARGUMENT} --inline-suppr --xml ${SOURCE_ARGS}
+                RESULT_VARIABLE CPPCHECK_EXIT_CODE
+                ERROR_VARIABLE ERROR_OUT
+                WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\")
+IF(NOT CPPCHECK_EXIT_CODE EQUAL 0)
+    MESSAGE(FATAL_ERROR \"Error executing cppcheck for target ${TARGET}, return code: \${CPPCHECK_EXIT_CODE}\")
+ENDIF()
+IF(ERROR_OUT)
+    MESSAGE(\"Detected errors:\\n\${ERROR_OUT}\")
+ENDIF()
+FILE(WRITE \"${CPPCHECK_REPORT_FILE}\" \"\${ERROR_OUT}\")
+"
+            )
+
+        ADD_CUSTOM_TARGET(${TARGET_NAME} ${CMAKE_COMMAND} -P "${CPPCHECK_WRAPPER_SCRIPT}"
+                          COMMENT "Generating cppcheck result ${TARGET_NAME}")
+
+        MESSAGE(STATUS "Generating cppcheck target with name ${TARGET_NAME}")
+
+    ENDIF()
+
+ENDFUNCTION()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/ParseArguments.cmake	Mon Feb 10 16:14:55 2014 +0000
@@ -0,0 +1,52 @@
+# Parse arguments passed to a function into several lists separated by
+# upper-case identifiers and options that do not have an associated list e.g.:
+#
+# SET(arguments
+#   hello OPTION3 world
+#   LIST3 foo bar
+#   OPTION2
+#   LIST1 fuz baz
+#   )
+# PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments})
+#
+# results in 7 distinct variables:
+#  * ARG_DEFAULT_ARGS: hello;world
+#  * ARG_LIST1: fuz;baz
+#  * ARG_LIST2:
+#  * ARG_LIST3: foo;bar
+#  * ARG_OPTION1: FALSE
+#  * ARG_OPTION2: TRUE
+#  * ARG_OPTION3: TRUE
+#
+# taken from http://www.cmake.org/Wiki/CMakeMacroParseArguments 
+
+MACRO(PARSE_ARGUMENTS prefix arg_names option_names)
+    SET(DEFAULT_ARGS)
+    FOREACH(arg_name ${arg_names})    
+        SET(${prefix}_${arg_name})
+    ENDFOREACH(arg_name)
+    FOREACH(option ${option_names})
+        SET(${prefix}_${option} FALSE)
+    ENDFOREACH(option)
+    
+    SET(current_arg_name DEFAULT_ARGS)
+    SET(current_arg_list)
+    FOREACH(arg ${ARGN})            
+        SET(larg_names ${arg_names})    
+        LIST(FIND larg_names "${arg}" is_arg_name)                   
+        IF (is_arg_name GREATER -1)
+            SET(${prefix}_${current_arg_name} ${current_arg_list})
+            SET(current_arg_name ${arg})
+            SET(current_arg_list)
+        ELSE (is_arg_name GREATER -1)
+            SET(loption_names ${option_names})    
+            LIST(FIND loption_names "${arg}" is_option)            
+            IF (is_option GREATER -1)
+                SET(${prefix}_${arg} TRUE)
+            ELSE (is_option GREATER -1)
+                SET(current_arg_list ${current_arg_list} ${arg})
+            ENDIF (is_option GREATER -1)
+        ENDIF (is_arg_name GREATER -1)
+    ENDFOREACH(arg)
+    SET(${prefix}_${current_arg_name} ${current_arg_list})
+ENDMACRO(PARSE_ARGUMENTS)

http://wald.intevation.org/projects/trustbridge/