diff options
39 files changed, 530 insertions, 243 deletions
diff --git a/Copyright.txt b/Copyright.txt index ed25419..4b6a7f5 100644 --- a/Copyright.txt +++ b/Copyright.txt @@ -62,6 +62,7 @@ The following individuals and institutions are among the Contributors: * Helio Chissini de Castro <helio@kde.org> * Ilya Lavrenov <ilya.lavrenov@itseez.com> * Insight Software Consortium <insightsoftwareconsortium.org> +* Intel Corporation <www.intel.com> * Jan Woetzel * Jordan Williams <jordan@jwillikers.com> * Julien Schueller diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index f07b4a6..ec73f9f 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -288,11 +288,10 @@ The options are: .. productionlist:: depfile depfile: `rule`* - rule: `targets` (`colon` `dependencies`?)? `eol` - colon: `separator`* ':' space `separator`* - targets: `target` (`separator` `target`)* + rule: `targets` (`:` (`separator` `dependencies`?)?)? `eol` + targets: `target` (`separator` `target`)* `separator`* target: `pathname` - dependencies: `dependency` (`separator` `dependency`)* + dependencies: `dependency` (`separator` `dependency`)* `separator`* dependency: `pathname` separator: (space | line_continue)+ line_continue: '\' `eol` diff --git a/Help/envvar/CUDAARCHS.rst b/Help/envvar/CUDAARCHS.rst index 82369cd..e9e6a42 100644 --- a/Help/envvar/CUDAARCHS.rst +++ b/Help/envvar/CUDAARCHS.rst @@ -6,8 +6,7 @@ CUDAARCHS .. include:: ENV_VAR.txt Value used to initialize :variable:`CMAKE_CUDA_ARCHITECTURES` on the first -configuration if it's not already defined. Subsequent runs will use the value -stored in the cache. +configuration. Subsequent runs will use the value stored in the cache. This is a semicolon-separated list of architectures as described in :prop_tgt:`CUDA_ARCHITECTURES`. diff --git a/Help/envvar/CUDAHOSTCXX.rst b/Help/envvar/CUDAHOSTCXX.rst index cf65927..74f5d48 100644 --- a/Help/envvar/CUDAHOSTCXX.rst +++ b/Help/envvar/CUDAHOSTCXX.rst @@ -8,9 +8,8 @@ CUDAHOSTCXX Preferred executable for compiling host code when compiling ``CUDA`` language files. Will only be used by CMake on the first configuration to determine ``CUDA`` host compiler, after which the value for ``CUDAHOSTCXX`` is -stored in the cache as :variable:`CMAKE_CUDA_HOST_COMPILER`. For any -configuration run (including the first), the environment variable will be -ignored if the :variable:`CMAKE_CUDA_HOST_COMPILER` variable is defined. +stored in the cache as :variable:`CMAKE_CUDA_HOST_COMPILER`. This environment +variable is preferred over :variable:`CMAKE_CUDA_HOST_COMPILER`. This environment variable is primarily meant for use with projects that enable ``CUDA`` as a first-class language. diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 51b092f..920bfe0 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -581,8 +581,6 @@ Variables for Languages /variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES /variable/CMAKE_LANG_LIBRARY_ARCHITECTURE /variable/CMAKE_LANG_LINK_EXECUTABLE - /variable/CMAKE_LANG_LINKER_PREFERENCE - /variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP /variable/CMAKE_LANG_OUTPUT_EXTENSION @@ -727,6 +725,8 @@ are subject to change, and not recommended for use in project code. /variable/CMAKE_LANG_COMPILER_ABI /variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID /variable/CMAKE_LANG_COMPILER_VERSION_INTERNAL + /variable/CMAKE_LANG_LINKER_PREFERENCE + /variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES /variable/CMAKE_LANG_PLATFORM_ID /variable/CMAKE_NOT_USING_CONFIG_FLAGS /variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION diff --git a/Help/prop_tgt/LANG_STANDARD.rst b/Help/prop_tgt/LANG_STANDARD.rst index bd377ec..c83da01 100644 --- a/Help/prop_tgt/LANG_STANDARD.rst +++ b/Help/prop_tgt/LANG_STANDARD.rst @@ -15,6 +15,13 @@ newer standard is specified than is supported by the compiler, then it will fallback to the latest supported standard. This "decay" behavior may be controlled with the :prop_tgt:`<LANG>_STANDARD_REQUIRED` target property. +Note that the actual language standard used may be higher than that specified +by ``<LANG>_STANDARD``, regardless of the value of +:prop_tgt:`<LANG>_STANDARD_REQUIRED`. In particular, +:ref:`transitive usage requirements <Target Usage Requirements>` or the use of +:manual:`compile features <cmake-compile-features(7)>` can raise the required +language standard above what ``<LANG>_STANDARD`` specifies. + These properties are initialized by the value of the :variable:`CMAKE_<LANG>_STANDARD` variable if it is set when a target is created. diff --git a/Help/prop_tgt/LANG_STANDARD_REQUIRED.rst b/Help/prop_tgt/LANG_STANDARD_REQUIRED.rst index 56ecef8..e61125b 100644 --- a/Help/prop_tgt/LANG_STANDARD_REQUIRED.rst +++ b/Help/prop_tgt/LANG_STANDARD_REQUIRED.rst @@ -11,16 +11,22 @@ The variations are: * :prop_tgt:`OBJCXX_STANDARD_REQUIRED` These properties specify whether the value of :prop_tgt:`<LANG>_STANDARD` is a -requirement. When ``OFF`` or unset, the :prop_tgt:`<LANG>_STANDARD` target +requirement. When false or unset, the :prop_tgt:`<LANG>_STANDARD` target property is treated as optional and may "decay" to a previous standard if the -requested is not available. +requested standard is not available. When ``<LANG>_STANDARD_REQUIRED`` is set +to true, :prop_tgt:`<LANG>_STANDARD` becomes a hard requirement and a fatal +error will be issued if that requirement cannot be met. + +Note that the actual language standard used may be higher than that specified +by :prop_tgt:`<LANG>_STANDARD`, regardless of the value of +``<LANG>_STANDARD_REQUIRED``. In particular, +:ref:`transitive usage requirements <Target Usage Requirements>` or the use of +:manual:`compile features <cmake-compile-features(7)>` can raise the required +language standard above what :prop_tgt:`<LANG>_STANDARD` specifies. These properties are initialized by the value of the :variable:`CMAKE_<LANG>_STANDARD_REQUIRED` variable if it is set when a target is created. -For supported CMake versions see the respective pages. -To control language standard versions see :prop_tgt:`<LANG>_STANDARD`. - See the :manual:`cmake-compile-features(7)` manual for information on compile features and a list of supported compilers. diff --git a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst index ff82f8b..a4035bd 100644 --- a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst +++ b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst @@ -1,6 +1,8 @@ CMAKE_<LANG>_LINKER_PREFERENCE ------------------------------ +An internal variable subject to change. + Preference value for linker language selection. The "linker language" for executable, shared library, and module diff --git a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst index dbbeb0a..df33edb 100644 --- a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst +++ b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst @@ -1,6 +1,8 @@ CMAKE_<LANG>_LINKER_PREFERENCE_PROPAGATES ----------------------------------------- +An internal variable subject to change. + True if :variable:`CMAKE_<LANG>_LINKER_PREFERENCE` propagates across targets. This is used when CMake selects a linker language for a target. diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake index 8479831..df71799 100644 --- a/Modules/CMakeDetermineCUDACompiler.cmake +++ b/Modules/CMakeDetermineCUDACompiler.cmake @@ -18,16 +18,16 @@ else() if(NOT CMAKE_CUDA_COMPILER) set(CMAKE_CUDA_COMPILER_INIT NOTFOUND) - # prefer the environment variable CUDACXX - if(NOT $ENV{CUDACXX} STREQUAL "") - get_filename_component(CMAKE_CUDA_COMPILER_INIT $ENV{CUDACXX} PROGRAM PROGRAM_ARGS CMAKE_CUDA_FLAGS_ENV_INIT) - if(CMAKE_CUDA_FLAGS_ENV_INIT) - set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CXX compiler") - endif() - if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT}) - message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}") - endif() + # prefer the environment variable CUDACXX + if(NOT $ENV{CUDACXX} STREQUAL "") + get_filename_component(CMAKE_CUDA_COMPILER_INIT $ENV{CUDACXX} PROGRAM PROGRAM_ARGS CMAKE_CUDA_FLAGS_ENV_INIT) + if(CMAKE_CUDA_FLAGS_ENV_INIT) + set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CUDA compiler") endif() + if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT}) + message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}") + endif() + endif() # finally list compilers to try if(NOT CMAKE_CUDA_COMPILER_INIT) diff --git a/Modules/CheckLinkerFlag.cmake b/Modules/CheckLinkerFlag.cmake index e85e43e..8319216 100644 --- a/Modules/CheckLinkerFlag.cmake +++ b/Modules/CheckLinkerFlag.cmake @@ -38,53 +38,8 @@ effect or even a specific one is beyond the scope of this module. #]=======================================================================] include_guard(GLOBAL) - -include(CMakeCheckCompilerFlagCommonPatterns) - -cmake_policy(PUSH) -cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced -cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST +include(Internal/CheckLinkerFlag) function(CHECK_LINKER_FLAG _lang _flag _var) - get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES) - if (NOT _lang IN_LIST _supported_languages) - message (SEND_ERROR "check_linker_flag: ${_lang}: unknown language.") - return() - endif() - - include (CheckSourceCompiles) - - set(CMAKE_REQUIRED_LINK_OPTIONS "${_flag}") - - # Normalize locale during test compilation. - set(_locale_vars LC_ALL LC_MESSAGES LANG) - foreach(v IN LISTS _locale_vars) - set(_locale_vars_saved_${v} "$ENV{${v}}") - set(ENV{${v}} C) - endforeach() - - if (_lang MATCHES "^(C|CXX)$") - set (_source "int main() { return 0; }") - elseif (_lang STREQUAL "Fortran") - set (_source " program test\n stop\n end program") - elseif (_lang MATCHES "CUDA") - set (_source "__host__ int main() { return 0; }") - elseif (_lang MATCHES "HIP") - set (_source "__host__ int main() { return 0; }") - elseif (_lang MATCHES "^(OBJC|OBJCXX)$") - set (_source "#ifndef __OBJC__\n# error \"Not an Objective-C++ compiler\"\n#endif\nint main(void) { return 0; }") - else() - message (SEND_ERROR "check_linker_flag: ${_lang}: unsupported language.") - return() - endif() - check_compiler_flag_common_patterns(_common_patterns) - - check_source_compiles(${_lang} "${_source}" ${_var} ${_common_patterns}) - - foreach(v IN LISTS _locale_vars) - set(ENV{${v}} ${_locale_vars_saved_${v}}) - endforeach() - set(${_var} "${${_var}}" PARENT_SCOPE) + cmake_check_linker_flag(${_lang} "${_flag}" ${_var}) endfunction() - -cmake_policy(POP) diff --git a/Modules/Internal/CheckCompilerFlag.cmake b/Modules/Internal/CheckCompilerFlag.cmake index f6a4cc9..3a67691 100644 --- a/Modules/Internal/CheckCompilerFlag.cmake +++ b/Modules/Internal/CheckCompilerFlag.cmake @@ -2,71 +2,15 @@ # file Copyright.txt or https://cmake.org/licensing for details. include_guard(GLOBAL) +include(Internal/CheckFlagCommonConfig) include(Internal/CheckSourceCompiles) include(CMakeCheckCompilerFlagCommonPatterns) -cmake_policy(PUSH) -cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced -cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST - function(CMAKE_CHECK_COMPILER_FLAG _lang _flag _var) - - if(_lang STREQUAL "C") - set(_lang_src "int main(void) { return 0; }") - set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C" - FAIL_REGEX "-Werror=.* argument .* is not valid for C") - elseif(_lang STREQUAL "CXX") - set(_lang_src "int main() { return 0; }") - set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" - FAIL_REGEX "-Werror=.* argument .* is not valid for C\\+\\+") - elseif(_lang STREQUAL "CUDA") - set(_lang_src "__host__ int main() { return 0; }") - set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" # Host GNU - FAIL_REGEX "argument unused during compilation: .*") # Clang - elseif(_lang STREQUAL "Fortran") - set(_lang_src " program test\n stop\n end program") - set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for Fortran") - elseif(_lang STREQUAL "HIP") - set(_lang_src "__host__ int main() { return 0; }") - set(_lang_fail_regex FAIL_REGEX "argument unused during compilation: .*") # Clang - elseif(_lang STREQUAL "OBJC") - set(_lang_src [=[ -#ifndef __OBJC__ -# error "Not an Objective-C compiler" -#endif -int main(void) { return 0; }]=]) - set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C" # GNU - FAIL_REGEX "argument unused during compilation: .*") # Clang - elseif(_lang STREQUAL "OBJCXX") - set(_lang_src [=[ -#ifndef __OBJC__ -# error "Not an Objective-C++ compiler" -#endif -int main(void) { return 0; }]=]) - set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C\\+\\+" # GNU - FAIL_REGEX "argument unused during compilation: .*") # Clang - elseif(_lang STREQUAL "ISPC") - set(_lang_src "float func(uniform int32, float a) { return a / 2.25; }") - else() - message (SEND_ERROR "check_compiler_flag: ${_lang}: unknown language.") - return() - endif() - - get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES) - if (NOT _lang IN_LIST _supported_languages) - message (SEND_ERROR "check_compiler_flag: ${_lang}: needs to be enabled before use.") - return() - endif() + cmake_check_flag_common_init("check_compiler_flag" ${_lang} _lang_src _lang_fail_regex) set(CMAKE_REQUIRED_DEFINITIONS ${_flag}) - # Normalize locale during test compilation. - set(_locale_vars LC_ALL LC_MESSAGES LANG) - foreach(v IN LISTS _locale_vars) - set(_locale_vars_saved_${v} "$ENV{${v}}") - set(ENV{${v}} C) - endforeach() - check_compiler_flag_common_patterns(_common_patterns) cmake_check_source_compiles(${_lang} "${_lang_src}" @@ -75,9 +19,5 @@ int main(void) { return 0; }]=]) ${_common_patterns} ) - foreach(v IN LISTS _locale_vars) - set(ENV{${v}} ${_locale_vars_saved_${v}}) - endforeach() -endfunction () - -cmake_policy(POP) + cmake_check_flag_common_finish() +endfunction() diff --git a/Modules/Internal/CheckFlagCommonConfig.cmake b/Modules/Internal/CheckFlagCommonConfig.cmake new file mode 100644 index 0000000..3934c02 --- /dev/null +++ b/Modules/Internal/CheckFlagCommonConfig.cmake @@ -0,0 +1,75 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +# Do NOT include this module directly into any of your code. It is meant as +# a library for Check*CompilerFlag.cmake and Check*LinkerFlag.cma modules. +# It's content may change in any way between releases. + +include_guard(GLOBAL) +cmake_policy(PUSH) +cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced +cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST + +macro(CMAKE_CHECK_FLAG_COMMON_INIT _FUNC _LANG _SRC _PATTERNS) + if("${_LANG}" STREQUAL "C") + set(${_SRC} "int main(void) { return 0; }") + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for C" + FAIL_REGEX "-Werror=.* argument .* is not valid for C") + elseif("${_LANG}" STREQUAL "CXX") + set(${_SRC} "int main() { return 0; }") + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" + FAIL_REGEX "-Werror=.* argument .* is not valid for C\\+\\+") + elseif("${_LANG}" STREQUAL "CUDA") + set(${_SRC} "__host__ int main() { return 0; }") + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" # Host GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang + elseif("${_LANG}" STREQUAL "Fortran") + set(${_SRC} " program test\n stop\n end program") + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Fortran") + elseif("${_LANG}" STREQUAL "HIP") + set(${_SRC} "__host__ int main() { return 0; }") + set(${_PATTERNS} FAIL_REGEX "argument unused during compilation: .*") # Clang + elseif("${_LANG}" STREQUAL "OBJC") + set(${_SRC} [=[ + #ifndef __OBJC__ + # error "Not an Objective-C compiler" + #endif + int main(void) { return 0; }]=]) + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C" # GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang + elseif("${_LANG}" STREQUAL "OBJCXX") + set(${_SRC} [=[ + #ifndef __OBJC__ + # error "Not an Objective-C++ compiler" + #endif + int main(void) { return 0; }]=]) + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C\\+\\+" # GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang + elseif("${_LANG}" STREQUAL "ISPC") + set(${_SRC} "float func(uniform int32, float a) { return a / 2.25; }") + else() + message (SEND_ERROR "${_FUNC}: ${_LANG}: unknown language.") + return() + endif() + + get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES) + if (NOT "${_LANG}" IN_LIST _supported_languages) + message (SEND_ERROR "${_FUNC}: ${_LANG}: needs to be enabled before use.") + return() + endif() + # Normalize locale during test compilation. + set(_locale_vars LC_ALL LC_MESSAGES LANG) + foreach(v IN LISTS _locale_vars) + set(_CMAKE_CHECK_FLAG_COMMON_CONFIG_locale_vars_saved_${v} "$ENV{${v}}") + set(ENV{${v}} C) + endforeach() +endmacro() + +macro(CMAKE_CHECK_FLAG_COMMON_FINISH) + foreach(v IN LISTS _CFCC_locale_vars) + set(ENV{${v}} ${_CMAKE_CHECK_FLAG_COMMON_CONFIG_locale_vars_saved_${v}}) + endforeach() +endmacro() + +cmake_policy(POP) diff --git a/Modules/Internal/CheckLinkerFlag.cmake b/Modules/Internal/CheckLinkerFlag.cmake new file mode 100644 index 0000000..285372a --- /dev/null +++ b/Modules/Internal/CheckLinkerFlag.cmake @@ -0,0 +1,35 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +include_guard(GLOBAL) +include(Internal/CheckFlagCommonConfig) +include(Internal/CheckSourceCompiles) +include(CMakeCheckCompilerFlagCommonPatterns) + +cmake_policy(PUSH) +cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced + +function(CMAKE_CHECK_LINKER_FLAG _lang _flag _var) + # link step supports less languages than the compiler + # so do a first check about the requested language + if (_lang STREQUAL "ISPC") + message (SEND_ERROR "check_linker_flag: ${_lang}: unsupported language.") + return() + endif() + + cmake_check_flag_common_init("check_linker_flag" ${_lang} _lang_src _lang_fail_regex) + + set(CMAKE_REQUIRED_LINK_OPTIONS "${_flag}") + + check_compiler_flag_common_patterns(_common_patterns) + cmake_check_source_compiles(${_lang} + "${_lang_src}" + ${_var} + ${_lang_fail_regex} + ${_common_patterns} + ) + + cmake_check_flag_common_finish() +endfunction() + +cmake_policy(POP) diff --git a/Modules/Platform/Windows-IntelLLVM.cmake b/Modules/Platform/Windows-IntelLLVM.cmake index b9ea037..4687bee 100644 --- a/Modules/Platform/Windows-IntelLLVM.cmake +++ b/Modules/Platform/Windows-IntelLLVM.cmake @@ -12,6 +12,19 @@ include(Platform/Windows-MSVC) macro(__windows_compiler_intel lang) __windows_compiler_msvc(${lang}) + # For DPCPP other offload cases, some link flags need to go to the compiler + # driver and others need to go to the linker. Pass the compiler linking flags + # in CMAKE_${lang}_LINK_FLAGS and linker flags in LINK_FLAGS + set(CMAKE_${lang}_LINK_EXECUTABLE + "${_CMAKE_VS_LINK_EXE}<CMAKE_${lang}_COMPILER> ${CMAKE_CL_NOLOGO} <CMAKE_${lang}_LINK_FLAGS> <OBJECTS> ${CMAKE_START_TEMP_FILE} /link /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}") + set(CMAKE_${lang}_CREATE_SHARED_LIBRARY + "${_CMAKE_VS_LINK_DLL}<CMAKE_${lang}_COMPILER> ${CMAKE_CL_NOLOGO} <CMAKE_${lang}_LINK_FLAGS> <OBJECTS> ${CMAKE_START_TEMP_FILE} -LD -link /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}") + if (NOT "${lang}" STREQUAL "Fortran" OR CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 2022.1) + # The Fortran driver does not support -fuse-ld=llvm-lib before compiler version 2022.1 + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY + "<CMAKE_${lang}_COMPILER> ${CMAKE_CL_NOLOGO} <CMAKE_${lang}_LINK_FLAGS> <OBJECTS> ${CMAKE_START_TEMP_FILE} -fuse-ld=llvm-lib -o <TARGET> -link <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}") + endif() + set(CMAKE_DEPFILE_FLAGS_${lang} "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>") set(CMAKE_${lang}_DEPFILE_FORMAT gcc) endmacro() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 0733b07..1e65a88 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 22) -set(CMake_VERSION_PATCH 20220114) +set(CMake_VERSION_PATCH 20220119) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx index 194ae0c..e588853 100644 --- a/Source/LexerParser/cmGccDepfileLexer.cxx +++ b/Source/LexerParser/cmGccDepfileLexer.cxx @@ -256,6 +256,7 @@ typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; +typedef uint64_t flex_uint64_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; @@ -420,7 +421,7 @@ struct yy_buffer_state /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - int yy_n_chars; + yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -497,7 +498,7 @@ static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, yy_size_t len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); @@ -544,12 +545,12 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ + yyleng = (yy_size_t) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 11 -#define YY_END_OF_BUFFER 12 +#define YY_NUM_RULES 12 +#define YY_END_OF_BUFFER 13 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -557,11 +558,11 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[26] = +static const flex_int16_t yy_accept[31] = { 0, - 0, 0, 12, 10, 8, 6, 10, 9, 10, 10, - 10, 8, 0, 6, 9, 1, 7, 5, 0, 3, - 2, 0, 4, 0, 0 + 0, 0, 13, 11, 9, 6, 11, 10, 11, 11, + 11, 9, 0, 6, 10, 1, 8, 7, 0, 0, + 5, 0, 3, 2, 0, 8, 0, 4, 0, 0 } ; static const YY_CHAR yy_ec[256] = @@ -601,36 +602,40 @@ static const YY_CHAR yy_meta[11] = 1, 2, 1, 1, 2, 1, 1, 1, 1, 3 } ; -static const flex_int16_t yy_base[28] = +static const flex_int16_t yy_base[33] = { 0, - 0, 0, 29, 35, 18, 35, 22, 18, 15, 0, - 8, 12, 16, 35, 11, 35, 0, 35, 13, 35, - 35, 16, 35, 22, 35, 31, 12 + 0, 0, 36, 46, 25, 46, 31, 27, 18, 9, + 17, 15, 25, 46, 17, 46, 0, 46, 15, 27, + 46, 14, 46, 46, 27, 46, 13, 46, 33, 46, + 42, 13 } ; -static const flex_int16_t yy_def[28] = +static const flex_int16_t yy_def[33] = { 0, - 25, 1, 25, 25, 26, 25, 25, 25, 25, 27, - 25, 26, 25, 25, 25, 25, 27, 25, 25, 25, - 25, 25, 25, 25, 0, 25, 25 + 30, 1, 30, 30, 31, 30, 30, 30, 30, 30, + 30, 31, 30, 30, 30, 30, 32, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, + 30, 30 } ; -static const flex_int16_t yy_nxt[46] = +static const flex_int16_t yy_nxt[57] = { 0, 4, 5, 6, 7, 5, 8, 4, 9, 10, 11, - 18, 19, 20, 17, 21, 18, 15, 22, 18, 19, - 23, 13, 16, 15, 14, 24, 20, 13, 25, 25, - 25, 22, 12, 12, 3, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25 + 17, 18, 19, 17, 17, 26, 21, 18, 20, 21, + 22, 23, 15, 24, 13, 16, 25, 21, 22, 26, + 27, 28, 15, 14, 13, 30, 29, 23, 30, 30, + 30, 30, 25, 12, 12, 3, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30 } ; -static const flex_int16_t yy_chk[46] = +static const flex_int16_t yy_chk[57] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 11, 11, 11, 27, 11, 19, 15, 11, 13, 13, - 22, 12, 9, 8, 7, 22, 24, 5, 3, 0, - 0, 24, 26, 26, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25 + 10, 10, 10, 10, 32, 27, 22, 19, 10, 11, + 11, 11, 15, 11, 12, 9, 11, 13, 13, 20, + 20, 25, 8, 7, 5, 3, 25, 29, 0, 0, + 0, 0, 29, 31, 31, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30 } ; /* The intent behind this definition is that it'll catch @@ -669,8 +674,8 @@ struct yyguts_t size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; - int yy_n_chars; - int yyleng_r; + yy_size_t yy_n_chars; + yy_size_t yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; @@ -717,7 +722,7 @@ FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); - int yyget_leng ( yyscan_t yyscanner ); + yy_size_t yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); @@ -790,7 +795,7 @@ static int input ( yyscan_t yyscanner ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - int n; \ + yy_size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -926,13 +931,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 26 ) + if ( yy_current_state >= 31 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 35 ); + while ( yy_base[yy_current_state] != 46 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -1006,34 +1011,46 @@ YY_RULE_SETUP } YY_BREAK case 7: +/* rule 7 can match eol */ YY_RULE_SETUP { - // A colon followed by space ends the rules and starts a new dependency. + // A colon ends the rules yyextra->newDependency(); + // A newline after colon terminates current rule. + yyextra->newEntry(); } YY_BREAK case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +{ + // A colon followed by space or line continuation ends the rules + // and starts a new dependency. + yyextra->newDependency(); + } + YY_BREAK +case 9: YY_RULE_SETUP { // Rules and dependencies are separated by blocks of whitespace. yyextra->newRuleOrDependency(); } YY_BREAK -case 9: +case 10: YY_RULE_SETUP { // Got a span of plain text. yyextra->addToCurrentPath(yytext); } YY_BREAK -case 10: +case 11: YY_RULE_SETUP { // Got an otherwise unmatched character. yyextra->addToCurrentPath(yytext); } YY_BREAK -case 11: +case 12: YY_RULE_SETUP ECHO; YY_BREAK @@ -1224,7 +1241,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else { - int num_to_read = + yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -1238,7 +1255,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( b->yy_is_our_buffer ) { - int new_size = b->yy_buf_size * 2; + yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -1296,7 +1313,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) @@ -1335,7 +1352,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 26 ) + if ( yy_current_state >= 31 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1364,11 +1381,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 26 ) + if ( yy_current_state >= 31 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 25); + yy_is_jam = (yy_current_state == 30); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -1389,7 +1406,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - int number_to_move = yyg->yy_n_chars + 2; + yy_size_t number_to_move = yyg->yy_n_chars + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = @@ -1441,7 +1458,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else { /* need more input */ - int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) @@ -1819,12 +1836,12 @@ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; - int i; + yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); @@ -1868,7 +1885,7 @@ static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) do \ { \ /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ + yy_size_t yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ @@ -1936,7 +1953,7 @@ FILE *yyget_out (yyscan_t yyscanner) /** Get the length of the current token. * @param yyscanner The scanner object. */ -int yyget_leng (yyscan_t yyscanner) +yy_size_t yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; diff --git a/Source/LexerParser/cmGccDepfileLexer.h b/Source/LexerParser/cmGccDepfileLexer.h index 7d34060..ab73ebc 100644 --- a/Source/LexerParser/cmGccDepfileLexer.h +++ b/Source/LexerParser/cmGccDepfileLexer.h @@ -258,6 +258,7 @@ typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; +typedef uint64_t flex_uint64_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; @@ -371,7 +372,7 @@ struct yy_buffer_state /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - int yy_n_chars; + yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -415,7 +416,7 @@ void yypop_buffer_state ( yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, yy_size_t len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); @@ -462,7 +463,7 @@ FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); - int yyget_leng ( yyscan_t yyscanner ); + yy_size_t yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l index aa2351e..6336b5f 100644 --- a/Source/LexerParser/cmGccDepfileLexer.in.l +++ b/Source/LexerParser/cmGccDepfileLexer.in.l @@ -48,8 +48,15 @@ NEWLINE \r?\n // A newline ends the current file name and the current rule. yyextra->newEntry(); } -:{WSPACE}+ { - // A colon followed by space ends the rules and starts a new dependency. +:{NEWLINE} { + // A colon ends the rules + yyextra->newDependency(); + // A newline after colon terminates current rule. + yyextra->newEntry(); + } +:({WSPACE}+|\\{NEWLINE}) { + // A colon followed by space or line continuation ends the rules + // and starts a new dependency. yyextra->newDependency(); } {WSPACE}+ { diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx index bf599ff..0cc4946 100644 --- a/Source/cmDependsCompiler.cxx +++ b/Source/cmDependsCompiler.cxx @@ -4,6 +4,7 @@ #include "cmDependsCompiler.h" #include <algorithm> +#include <iterator> #include <map> #include <memory> #include <string> @@ -111,9 +112,13 @@ bool cmDependsCompiler::CheckDependencies( // copy depends for each target, except first one, which can be // moved for (auto index = entry.rules.size() - 1; index > 0; --index) { - dependencies[entry.rules[index]] = depends; + auto& rule_deps = dependencies[entry.rules[index]]; + rule_deps.insert(rule_deps.end(), depends.cbegin(), + depends.cend()); } - dependencies[entry.rules.front()] = std::move(depends); + auto& rule_deps = dependencies[entry.rules.front()]; + std::move(depends.cbegin(), depends.cend(), + std::back_inserter(rule_deps)); } } else { if (format == "msvc"_s) { diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx index afa8e9b..34c8824 100644 --- a/Source/cmGccDepfileLexerHelper.cxx +++ b/Source/cmGccDepfileLexerHelper.cxx @@ -113,6 +113,24 @@ void cmGccDepfileLexerHelper::addToCurrentPath(const char* s) void cmGccDepfileLexerHelper::sanitizeContent() { for (auto it = this->Content.begin(); it != this->Content.end();) { + // Remove empty paths and normalize windows paths + for (auto pit = it->paths.begin(); pit != it->paths.end();) { + if (pit->empty()) { + pit = it->paths.erase(pit); + } else { +#if defined(_WIN32) + // Unescape the colon following the drive letter. + // Some versions of GNU compilers can escape this character. + // c\:\path must be transformed to c:\path + if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' && + std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' && + (*pit)[2] == ':') { + pit->erase(1, 1); + } +#endif + ++pit; + } + } // Remove empty rules for (auto rit = it->rules.begin(); rit != it->rules.end();) { if (rit->empty()) { @@ -121,28 +139,10 @@ void cmGccDepfileLexerHelper::sanitizeContent() ++rit; } } - // Remove the entry if rules are empty - if (it->rules.empty()) { + // Remove the entry if rules are empty or do not have any paths + if (it->rules.empty() || it->paths.empty()) { it = this->Content.erase(it); } else { - // Remove empty paths and normalize windows paths - for (auto pit = it->paths.begin(); pit != it->paths.end();) { - if (pit->empty()) { - pit = it->paths.erase(pit); - } else { -#if defined(_WIN32) - // Unescape the colon following the drive letter. - // Some versions of GNU compilers can escape this character. - // c\:\path must be transformed to c:\path - if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' && - std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' && - (*pit)[2] == ':') { - pit->erase(1, 1); - } -#endif - ++pit; - } - } ++it; } } diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx index 4032596..81a6507 100644 --- a/Source/cmTransformDepfile.cxx +++ b/Source/cmTransformDepfile.cxx @@ -4,7 +4,6 @@ #include <algorithm> #include <functional> -#include <memory> #include <string> #include <type_traits> #include <utility> @@ -95,14 +94,16 @@ void WriteMSBuildAdditionalInputs(cmsys::ofstream& fout, // Write the format expected by MSBuild CustomBuild AdditionalInputs. const char* sep = ""; - for (std::string path : content.front().paths) { - if (!cmSystemTools::FileIsFullPath(path)) { - path = - cmSystemTools::CollapseFullPath(path, lg.GetCurrentBinaryDirectory()); + for (const auto& c : content) { + for (std::string path : c.paths) { + if (!cmSystemTools::FileIsFullPath(path)) { + path = cmSystemTools::CollapseFullPath(path, + lg.GetCurrentBinaryDirectory()); + } + std::replace(path.begin(), path.end(), '/', '\\'); + fout << sep << path; + sep = ";"; } - std::replace(path.begin(), path.end(), '/', '\\'); - fout << sep << path; - sep = ";"; } fout << "\n"; } diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake index e4fdb4a..19c09c8 100644 --- a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake +++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake @@ -24,6 +24,13 @@ add_library(toplib STATIC toplib.c) add_subdirectory(DepfileSubdir) +add_custom_command( + OUTPUT toplib2.c + DEPFILE toplib2.c.d + COMMAND ${CMAKE_COMMAND} -DOUTFILE=toplib2.c -DINFILE=toplibdep2.txt -DDEPFILE=toplib2.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile2.cmake" + ) +add_library(toplib2 STATIC toplib2.c) + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT " function(check_exists file) if(NOT EXISTS \"\${file}\") @@ -43,6 +50,7 @@ set(check_pairs \"${CMAKE_BINARY_DIR}/topcc.c|${CMAKE_BINARY_DIR}/topccdep.txt\" \"$<TARGET_FILE:topexe>|${CMAKE_BINARY_DIR}/topexedep.txt\" \"$<TARGET_FILE:toplib>|${CMAKE_BINARY_DIR}/toplibdep.txt\" + \"$<TARGET_FILE:toplib2>|${CMAKE_BINARY_DIR}/toplibdep2.txt\" \"${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c|${CMAKE_BINARY_DIR}/DepfileSubdir/subccdep.txt\" \"$<TARGET_FILE:subexe>|${CMAKE_BINARY_DIR}/DepfileSubdir/subexedep.txt\" \"$<TARGET_FILE:sublib>|${CMAKE_BINARY_DIR}/DepfileSubdir/sublibdep.txt\" @@ -53,6 +61,7 @@ if(check_step EQUAL 3) \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/topcc.c\" \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:topexe>\" \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:toplib>\" + \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:toplib2>\" \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c\" \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:subexe>\" \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:sublib>\" diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake index 0dfe78e..a33a03c 100644 --- a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake +++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake @@ -5,6 +5,7 @@ file(REMOVE "${RunCMake_TEST_BINARY_DIR}/step3.timestamp") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt") +file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep2.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt") diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake index c711514..ee7df7b 100644 --- a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake +++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake @@ -1,6 +1,7 @@ file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt") +file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep2.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt") file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt") diff --git a/Tests/RunCMake/BuildDepends/WriteDepfile2.cmake b/Tests/RunCMake/BuildDepends/WriteDepfile2.cmake new file mode 100644 index 0000000..f7898f6 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/WriteDepfile2.cmake @@ -0,0 +1,8 @@ +file(WRITE "${OUTFILE}" [[int main(void) +{ + return 0; +} +]]) +string(REPLACE [[ ]] [[\ ]] OUTFILE "${OUTFILE}") +string(REPLACE [[ ]] [[\ ]] INFILE "${INFILE}") +file(WRITE "${DEPFILE}" "${OUTFILE}:\n${OUTFILE}: ${INFILE}\n") diff --git a/Tests/RunCMake/CheckCompilerFlag/NonExistentLanguage-stderr.txt b/Tests/RunCMake/CheckCompilerFlag/NonExistentLanguage-stderr.txt index 89d0565..99491e8 100644 --- a/Tests/RunCMake/CheckCompilerFlag/NonExistentLanguage-stderr.txt +++ b/Tests/RunCMake/CheckCompilerFlag/NonExistentLanguage-stderr.txt @@ -1,2 +1,2 @@ -CMake Error at .*CheckCompilerFlag\.cmake:[0-9]+ \(message\): +CMake Error at .*CheckFlagCommonConfig\.cmake:[0-9]+ \(message\): check_compiler_flag: FAKE_LANG: unknown language. diff --git a/Tests/RunCMake/CheckCompilerFlag/NotEnabledLanguage-stderr.txt b/Tests/RunCMake/CheckCompilerFlag/NotEnabledLanguage-stderr.txt index 23dd4a1..82c47e3 100644 --- a/Tests/RunCMake/CheckCompilerFlag/NotEnabledLanguage-stderr.txt +++ b/Tests/RunCMake/CheckCompilerFlag/NotEnabledLanguage-stderr.txt @@ -1,2 +1,2 @@ -CMake Error at .*CheckCompilerFlag\.cmake:[0-9]+ \(message\): +CMake Error at .*CheckFlagCommonConfig\.cmake:[0-9]+ \(message\): check_compiler_flag: C: needs to be enabled before use. diff --git a/Tests/RunCMake/find_library/FromPATHEnv.cmake b/Tests/RunCMake/find_library/FromPATHEnv.cmake index c24e640..ba4dd37 100644 --- a/Tests/RunCMake/find_library/FromPATHEnv.cmake +++ b/Tests/RunCMake/find_library/FromPATHEnv.cmake @@ -1,6 +1,8 @@ list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .a) set(ENV_PATH "$ENV{PATH}") +set(ENV_CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}") +set(ENV{CMAKE_PREFIX_PATH} "") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib/libcreated.a" "created") @@ -33,3 +35,4 @@ foreach(path "/does_not_exist" "/lib" "") endforeach() set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH ON) set(ENV{PATH} "${ENV_PATH}") +set(ENV{CMAKE_PREFIX_PATH} "${ENV_CMAKE_PREFIX_PATH}") diff --git a/Tests/RunCMake/find_library/FromPATHEnvDebugVar.cmake b/Tests/RunCMake/find_library/FromPATHEnvDebugVar.cmake index c24e640..ba4dd37 100644 --- a/Tests/RunCMake/find_library/FromPATHEnvDebugVar.cmake +++ b/Tests/RunCMake/find_library/FromPATHEnvDebugVar.cmake @@ -1,6 +1,8 @@ list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .a) set(ENV_PATH "$ENV{PATH}") +set(ENV_CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}") +set(ENV{CMAKE_PREFIX_PATH} "") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib/libcreated.a" "created") @@ -33,3 +35,4 @@ foreach(path "/does_not_exist" "/lib" "") endforeach() set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH ON) set(ENV{PATH} "${ENV_PATH}") +set(ENV{CMAKE_PREFIX_PATH} "${ENV_CMAKE_PREFIX_PATH}") diff --git a/Tests/RunCMake/find_library/FromPrefixPath.cmake b/Tests/RunCMake/find_library/FromPrefixPath.cmake index 04763a9..52814e8 100644 --- a/Tests/RunCMake/find_library/FromPrefixPath.cmake +++ b/Tests/RunCMake/find_library/FromPrefixPath.cmake @@ -1,7 +1,9 @@ list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .a) set(ENV_PATH "$ENV{PATH}") +set(ENV_CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}") set(ENV{PATH} "") +set(ENV{CMAKE_PREFIX_PATH} "") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib/libcreated.a" "created") @@ -22,3 +24,4 @@ foreach(path "/does_not_exist" "/lib" "") endforeach() set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH ON) set(ENV{PATH} "${ENV_PATH}") +set(ENV{CMAKE_PREFIX_PATH} "${ENV_CMAKE_PREFIX_PATH}") diff --git a/Utilities/Scripts/update-expat.bash b/Utilities/Scripts/update-expat.bash index a052c0e..53449d0 100755 --- a/Utilities/Scripts/update-expat.bash +++ b/Utilities/Scripts/update-expat.bash @@ -8,7 +8,7 @@ readonly name="expat" readonly ownership="Expat Upstream <kwrobot@kitware.com>" readonly subtree="Utilities/cmexpat" readonly repo="https://github.com/libexpat/libexpat.git" -readonly tag="R_2_4_1" +readonly tag="R_2_4_3" readonly shortlog=false readonly paths=" expat/lib/asciitab.h diff --git a/Utilities/cmexpat/ConfigureChecks.cmake b/Utilities/cmexpat/ConfigureChecks.cmake index 4da252c..341bab7 100644 --- a/Utilities/cmexpat/ConfigureChecks.cmake +++ b/Utilities/cmexpat/ConfigureChecks.cmake @@ -2,6 +2,7 @@ include(CheckCCompilerFlag) include(CheckCSourceCompiles) include(CheckIncludeFile) include(CheckIncludeFiles) +include(CheckLibraryExists) include(CheckSymbolExists) include(TestBigEndian) diff --git a/Utilities/cmexpat/README.md b/Utilities/cmexpat/README.md index 251dc8a..6fdd614 100644 --- a/Utilities/cmexpat/README.md +++ b/Utilities/cmexpat/README.md @@ -5,7 +5,7 @@ [![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases) -# Expat, Release 2.4.1 +# Expat, Release 2.4.3 This is Expat, a C library for parsing XML, started by [James Clark](https://en.wikipedia.org/wiki/James_Clark_%28programmer%29) in 1997. diff --git a/Utilities/cmexpat/lib/expat.h b/Utilities/cmexpat/lib/expat.h index b7d6d35..0f021e2 100644 --- a/Utilities/cmexpat/lib/expat.h +++ b/Utilities/cmexpat/lib/expat.h @@ -11,7 +11,7 @@ Copyright (c) 2000-2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net> Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net> Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net> - Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org> + Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org> Copyright (c) 2016 Cristian Rodríguez <crrodriguez@opensuse.org> Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de> Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk> @@ -1041,7 +1041,7 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 1 +#define XML_MICRO_VERSION 3 #ifdef __cplusplus } diff --git a/Utilities/cmexpat/lib/xmlparse.c b/Utilities/cmexpat/lib/xmlparse.c index 5ba56eae..b2f5fc6 100644 --- a/Utilities/cmexpat/lib/xmlparse.c +++ b/Utilities/cmexpat/lib/xmlparse.c @@ -1,4 +1,4 @@ -/* 8539b9040d9d901366a62560a064af7cb99811335784b363abc039c5b0ebc416 (2.4.1+) +/* 9ca2a2fedc35bcb13ba9a134ba5e173020bc2ff5f5a311abf742cec7da1ff26a (2.4.3+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -13,7 +13,7 @@ Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net> Copyright (c) 2005-2009 Steven Solie <ssolie@users.sourceforge.net> Copyright (c) 2016 Eric Rahm <erahm@mozilla.com> - Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org> + Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org> Copyright (c) 2016 Gaurav <g.gupta@samsung.com> Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de> Copyright (c) 2016 Gustavo Grieco <gustavo.grieco@imag.fr> @@ -32,6 +32,7 @@ Copyright (c) 2019 David Loffredo <loffredo@steptools.com> Copyright (c) 2019-2020 Ben Wagner <bungeman@chromium.org> Copyright (c) 2019 Vadim Zeitlin <vadim@zeitlins.org> + Copyright (c) 2021 Dong-hee Na <donghee.na@python.org> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -54,6 +55,10 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#define XML_BUILDING_EXPAT 1 + +#include <expat_config.h> + #if ! defined(_GNU_SOURCE) # define _GNU_SOURCE 1 /* syscall prototype */ #endif @@ -84,14 +89,10 @@ # include <errno.h> #endif -#define XML_BUILDING_EXPAT 1 - #ifdef _WIN32 # include "winconfig.h" #endif -#include <expat_config.h> - #include "ascii.h" #include "expat.h" #include "siphash.h" @@ -3260,13 +3261,38 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, /* get the attributes from the tokenizer */ n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts); + + /* Detect and prevent integer overflow */ + if (n > INT_MAX - nDefaultAtts) { + return XML_ERROR_NO_MEMORY; + } + if (n + nDefaultAtts > parser->m_attsSize) { int oldAttsSize = parser->m_attsSize; ATTRIBUTE *temp; #ifdef XML_ATTR_INFO XML_AttrInfo *temp2; #endif + + /* Detect and prevent integer overflow */ + if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE) + || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) { + return XML_ERROR_NO_MEMORY; + } + parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) { + parser->m_attsSize = oldAttsSize; + return XML_ERROR_NO_MEMORY; + } +#endif + temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, parser->m_attsSize * sizeof(ATTRIBUTE)); if (temp == NULL) { @@ -3275,6 +3301,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } parser->m_atts = temp; #ifdef XML_ATTR_INFO + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +# if UINT_MAX >= SIZE_MAX + if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) { + parser->m_attsSize = oldAttsSize; + return XML_ERROR_NO_MEMORY; + } +# endif + temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, parser->m_attsSize * sizeof(XML_AttrInfo)); if (temp2 == NULL) { @@ -3413,7 +3450,13 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, if (nPrefixes) { int j; /* hash table index */ unsigned long version = parser->m_nsAttsVersion; - int nsAttsSize = (int)1 << parser->m_nsAttsPower; + + /* Detect and prevent invalid shift */ + if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) { + return XML_ERROR_NO_MEMORY; + } + + unsigned int nsAttsSize = 1u << parser->m_nsAttsPower; unsigned char oldNsAttsPower = parser->m_nsAttsPower; /* size of hash table must be at least 2 * (# of prefixed attributes) */ if ((nPrefixes << 1) @@ -3424,7 +3467,28 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, ; if (parser->m_nsAttsPower < 3) parser->m_nsAttsPower = 3; - nsAttsSize = (int)1 << parser->m_nsAttsPower; + + /* Detect and prevent invalid shift */ + if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) { + /* Restore actual size of memory in m_nsAtts */ + parser->m_nsAttsPower = oldNsAttsPower; + return XML_ERROR_NO_MEMORY; + } + + nsAttsSize = 1u << parser->m_nsAttsPower; + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) { + /* Restore actual size of memory in m_nsAtts */ + parser->m_nsAttsPower = oldNsAttsPower; + return XML_ERROR_NO_MEMORY; + } +#endif + temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT)); if (! temp) { @@ -3582,9 +3646,31 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, tagNamePtr->prefixLen = prefixLen; for (i = 0; localPart[i++];) ; /* i includes null terminator */ + + /* Detect and prevent integer overflow */ + if (binding->uriLen > INT_MAX - prefixLen + || i > INT_MAX - (binding->uriLen + prefixLen)) { + return XML_ERROR_NO_MEMORY; + } + n = i + binding->uriLen + prefixLen; if (n > binding->uriAlloc) { TAG *p; + + /* Detect and prevent integer overflow */ + if (n > INT_MAX - EXPAND_SPARE) { + return XML_ERROR_NO_MEMORY; + } + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + return XML_ERROR_NO_MEMORY; + } +#endif + uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); if (! uri) return XML_ERROR_NO_MEMORY; @@ -3680,6 +3766,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, if (parser->m_freeBindingList) { b = parser->m_freeBindingList; if (len > b->uriAlloc) { + /* Detect and prevent integer overflow */ + if (len > INT_MAX - EXPAND_SPARE) { + return XML_ERROR_NO_MEMORY; + } + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + return XML_ERROR_NO_MEMORY; + } +#endif + XML_Char *temp = (XML_Char *)REALLOC( parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (temp == NULL) @@ -3692,6 +3793,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, b = (BINDING *)MALLOC(parser, sizeof(BINDING)); if (! b) return XML_ERROR_NO_MEMORY; + + /* Detect and prevent integer overflow */ + if (len > INT_MAX - EXPAND_SPARE) { + return XML_ERROR_NO_MEMORY; + } + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + return XML_ERROR_NO_MEMORY; + } +#endif + b->uri = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (! b->uri) { @@ -5018,6 +5134,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, if (parser->m_prologState.level >= parser->m_groupSize) { if (parser->m_groupSize) { { + /* Detect and prevent integer overflow */ + if (parser->m_groupSize > (unsigned int)(-1) / 2u) { + return XML_ERROR_NO_MEMORY; + } + char *const new_connector = (char *)REALLOC( parser, parser->m_groupConnector, parser->m_groupSize *= 2); if (new_connector == NULL) { @@ -5028,6 +5149,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, } if (dtd->scaffIndex) { + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) { + return XML_ERROR_NO_MEMORY; + } +#endif + int *const new_scaff_index = (int *)REALLOC( parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int)); if (new_scaff_index == NULL) @@ -6098,7 +6229,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, } } else { DEFAULT_ATTRIBUTE *temp; + + /* Detect and prevent integer overflow */ + if (type->allocDefaultAtts > INT_MAX / 2) { + return 0; + } + int count = type->allocDefaultAtts * 2; + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) { + return 0; + } +#endif + temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); if (temp == NULL) @@ -6749,8 +6897,20 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { /* check for overflow (table is half full) */ if (table->used >> (table->power - 1)) { unsigned char newPower = table->power + 1; + + /* Detect and prevent invalid shift */ + if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) { + return NULL; + } + size_t newSize = (size_t)1 << newPower; unsigned long newMask = (unsigned long)newSize - 1; + + /* Detect and prevent integer overflow */ + if (newSize > (size_t)(-1) / sizeof(NAMED *)) { + return NULL; + } + size_t tsize = newSize * sizeof(NAMED *); NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); if (! newV) @@ -7100,6 +7260,20 @@ nextScaffoldPart(XML_Parser parser) { if (dtd->scaffCount >= dtd->scaffSize) { CONTENT_SCAFFOLD *temp; if (dtd->scaffold) { + /* Detect and prevent integer overflow */ + if (dtd->scaffSize > UINT_MAX / 2u) { + return -1; + } + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) { + return -1; + } +#endif + temp = (CONTENT_SCAFFOLD *)REALLOC( parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); if (temp == NULL) @@ -7169,8 +7343,26 @@ build_model(XML_Parser parser) { XML_Content *ret; XML_Content *cpos; XML_Char *str; - int allocsize = (dtd->scaffCount * sizeof(XML_Content) - + (dtd->contentStringLen * sizeof(XML_Char))); + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) { + return NULL; + } + if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) { + return NULL; + } +#endif + if (dtd->scaffCount * sizeof(XML_Content) + > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) { + return NULL; + } + + const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content) + + (dtd->contentStringLen * sizeof(XML_Char))); ret = (XML_Content *)MALLOC(parser, allocsize); if (! ret) diff --git a/Utilities/cmexpat/lib/xmlrole.c b/Utilities/cmexpat/lib/xmlrole.c index 08173b0..77746ee 100644 --- a/Utilities/cmexpat/lib/xmlrole.c +++ b/Utilities/cmexpat/lib/xmlrole.c @@ -15,6 +15,7 @@ Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org> Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk> Copyright (c) 2019 David Loffredo <loffredo@steptools.com> + Copyright (c) 2021 Dong-hee Na <donghee.na@python.org> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -37,14 +38,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include <expat_config.h> + #include <stddef.h> #ifdef _WIN32 # include "winconfig.h" #endif -#include <expat_config.h> - #include "expat_external.h" #include "internal.h" #include "xmlrole.h" diff --git a/Utilities/cmexpat/lib/xmltok.c b/Utilities/cmexpat/lib/xmltok.c index f2b6b40..502ca1a 100644 --- a/Utilities/cmexpat/lib/xmltok.c +++ b/Utilities/cmexpat/lib/xmltok.c @@ -20,6 +20,7 @@ Copyright (c) 2017 Benbuck Nason <bnason@netflix.com> Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com> Copyright (c) 2019 David Loffredo <loffredo@steptools.com> + Copyright (c) 2021 Dong-hee Na <donghee.na@python.org> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -42,6 +43,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include <expat_config.h> + #include <stddef.h> #include <string.h> /* memcpy */ #include <stdbool.h> @@ -50,8 +53,6 @@ # include "winconfig.h" #endif -#include <expat_config.h> - #include "expat_external.h" #include "internal.h" #include "xmltok.h" diff --git a/Utilities/cmexpat/lib/xmltok_ns.c b/Utilities/cmexpat/lib/xmltok_ns.c index 5fd8392..fbdd3e3 100644 --- a/Utilities/cmexpat/lib/xmltok_ns.c +++ b/Utilities/cmexpat/lib/xmltok_ns.c @@ -11,7 +11,7 @@ Copyright (c) 2002 Greg Stein <gstein@users.sourceforge.net> Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net> Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net> - Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org> + Copyright (c) 2017-2021 Sebastian Pipping <sebastian@pipping.org> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -93,7 +93,7 @@ NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, static const ENCODING * NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) { # define ENCODING_MAX 128 - char buf[ENCODING_MAX]; + char buf[ENCODING_MAX] = ""; char *p = buf; int i; XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); |